1 /*
2  * This file is part of libmodulemd
3  * Copyright (C) 2018 Red Hat, Inc.
4  *
5  * Fedora-License-Identifier: MIT
6  * SPDX-2.0-License-Identifier: MIT
7  * SPDX-3.0-License-Identifier: MIT
8  *
9  * This program is free software.
10  * For more information on the license, see COPYING.
11  * For more information on free software, see <https://www.gnu.org/philosophy/free-sw.en.html>.
12  */
13 
14 #include "modulemd-buildopts.h"
15 #include "modulemd-component-module.h"
16 #include "modulemd-component-rpm.h"
17 #include "modulemd-component.h"
18 #include "modulemd-errors.h"
19 #include "modulemd-module-stream-v2.h"
20 #include "modulemd-module-stream.h"
21 #include "modulemd-profile.h"
22 #include "modulemd-rpm-map-entry.h"
23 #include "modulemd-service-level.h"
24 #include "modulemd-translation-entry.h"
25 #include "private/modulemd-buildopts-private.h"
26 #include "private/modulemd-component-module-private.h"
27 #include "private/modulemd-component-private.h"
28 #include "private/modulemd-component-rpm-private.h"
29 #include "private/modulemd-dependencies-private.h"
30 #include "private/modulemd-module-stream-private.h"
31 #include "private/modulemd-module-stream-v2-private.h"
32 #include "private/modulemd-profile-private.h"
33 #include "private/modulemd-rpm-map-entry-private.h"
34 #include "private/modulemd-service-level-private.h"
35 #include "private/modulemd-subdocument-info-private.h"
36 #include "private/modulemd-util.h"
37 #include "private/modulemd-yaml.h"
38 
39 
40 G_DEFINE_TYPE (ModulemdModuleStreamV2,
41                modulemd_module_stream_v2,
42                MODULEMD_TYPE_MODULE_STREAM)
43 
44 enum
45 {
46   PROP_0,
47   PROP_ARCH,
48   PROP_BUILDOPTS,
49   PROP_COMMUNITY,
50   PROP_DOCUMENTATION,
51   PROP_TRACKER,
52   PROP_STATIC_CONTEXT,
53   N_PROPS
54 };
55 
56 static GParamSpec *properties[N_PROPS];
57 
58 ModulemdModuleStreamV2 *
modulemd_module_stream_v2_new(const gchar * module_name,const gchar * module_stream)59 modulemd_module_stream_v2_new (const gchar *module_name,
60                                const gchar *module_stream)
61 {
62   // clang-format off
63   return g_object_new (MODULEMD_TYPE_MODULE_STREAM_V2,
64                        "module-name", module_name,
65                        "stream-name", module_stream,
66                        NULL);
67   // clang-format on
68 }
69 
70 
71 static void
modulemd_module_stream_v2_finalize(GObject * object)72 modulemd_module_stream_v2_finalize (GObject *object)
73 {
74   ModulemdModuleStreamV2 *self = MODULEMD_MODULE_STREAM_V2 (object);
75 
76   /* Properties */
77   g_clear_object (&self->buildopts);
78   g_clear_pointer (&self->community, g_free);
79   g_clear_pointer (&self->description, g_free);
80   g_clear_pointer (&self->documentation, g_free);
81   g_clear_pointer (&self->summary, g_free);
82   g_clear_pointer (&self->tracker, g_free);
83 
84   /* Internal Data Structures */
85   g_clear_pointer (&self->module_components, g_hash_table_unref);
86   g_clear_pointer (&self->rpm_components, g_hash_table_unref);
87 
88   g_clear_pointer (&self->content_licenses, g_hash_table_unref);
89   g_clear_pointer (&self->module_licenses, g_hash_table_unref);
90 
91   g_clear_pointer (&self->profiles, g_hash_table_unref);
92 
93   g_clear_pointer (&self->rpm_api, g_hash_table_unref);
94 
95   g_clear_pointer (&self->rpm_artifacts, g_hash_table_unref);
96 
97   g_clear_pointer (&self->rpm_artifact_map, g_hash_table_unref);
98 
99   g_clear_pointer (&self->rpm_filters, g_hash_table_unref);
100 
101   g_clear_pointer (&self->demodularized_rpms, g_hash_table_unref);
102 
103   g_clear_pointer (&self->servicelevels, g_hash_table_unref);
104 
105   g_clear_pointer (&self->dependencies, g_ptr_array_unref);
106 
107   g_clear_pointer (&self->obsoletes, g_object_unref);
108 
109   g_clear_pointer (&self->xmd, g_variant_unref);
110 
111   G_OBJECT_CLASS (modulemd_module_stream_v2_parent_class)->finalize (object);
112 }
113 
114 
115 static gboolean
modulemd_module_stream_v2_equals(ModulemdModuleStream * self_1,ModulemdModuleStream * self_2)116 modulemd_module_stream_v2_equals (ModulemdModuleStream *self_1,
117                                   ModulemdModuleStream *self_2)
118 {
119   ModulemdModuleStreamV2 *v2_self_1 = NULL;
120   ModulemdModuleStreamV2 *v2_self_2 = NULL;
121 
122   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self_1), FALSE);
123   v2_self_1 = MODULEMD_MODULE_STREAM_V2 (self_1);
124   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self_2), FALSE);
125   v2_self_2 = MODULEMD_MODULE_STREAM_V2 (self_2);
126 
127   if (!MODULEMD_MODULE_STREAM_CLASS (modulemd_module_stream_v2_parent_class)
128          ->equals (self_1, self_2))
129     {
130       return FALSE;
131     }
132 
133   /*Check property equality*/
134   if (g_strcmp0 (v2_self_1->community, v2_self_2->community) != 0)
135     {
136       return FALSE;
137     }
138 
139   if (g_strcmp0 (v2_self_1->description, v2_self_2->description) != 0)
140     {
141       return FALSE;
142     }
143 
144   if (g_strcmp0 (v2_self_1->documentation, v2_self_2->documentation) != 0)
145     {
146       return FALSE;
147     }
148 
149   if (g_strcmp0 (v2_self_1->summary, v2_self_2->summary) != 0)
150     {
151       return FALSE;
152     }
153 
154   if (g_strcmp0 (v2_self_1->tracker, v2_self_2->tracker) != 0)
155     {
156       return FALSE;
157     }
158 
159   /* Test the negations of static_context just in case somehow they are
160    * different non-zero values
161    */
162   if (!v2_self_1->static_context != !v2_self_2->static_context)
163     {
164       return FALSE;
165     }
166 
167   if (!modulemd_buildopts_equals (v2_self_1->buildopts, v2_self_2->buildopts))
168     {
169       return FALSE;
170     }
171 
172   if (!modulemd_hash_table_equals (v2_self_1->rpm_components,
173                                    v2_self_2->rpm_components,
174                                    modulemd_component_equals_wrapper))
175     {
176       return FALSE;
177     }
178 
179   if (!modulemd_hash_table_equals (v2_self_1->module_components,
180                                    v2_self_2->module_components,
181                                    modulemd_component_equals_wrapper))
182     {
183       return FALSE;
184     }
185 
186   if (!modulemd_hash_table_sets_are_equal (v2_self_1->module_licenses,
187                                            v2_self_2->module_licenses))
188     {
189       return FALSE;
190     }
191 
192   if (!modulemd_hash_table_sets_are_equal (v2_self_1->content_licenses,
193                                            v2_self_2->content_licenses))
194     {
195       return FALSE;
196     }
197 
198   if (!modulemd_hash_table_equals (v2_self_1->profiles,
199                                    v2_self_2->profiles,
200                                    modulemd_profile_equals_wrapper))
201     {
202       return FALSE;
203     }
204 
205   if (!modulemd_hash_table_sets_are_equal (v2_self_1->rpm_api,
206                                            v2_self_2->rpm_api))
207     {
208       return FALSE;
209     }
210 
211   if (!modulemd_hash_table_sets_are_equal (v2_self_1->rpm_artifacts,
212                                            v2_self_2->rpm_artifacts))
213     {
214       return FALSE;
215     }
216 
217   if (!modulemd_hash_table_sets_are_equal (v2_self_1->rpm_filters,
218                                            v2_self_2->rpm_filters))
219     {
220       return FALSE;
221     }
222 
223   if (!modulemd_hash_table_sets_are_equal (v2_self_1->demodularized_rpms,
224                                            v2_self_2->demodularized_rpms))
225     {
226       return FALSE;
227     }
228 
229   if (!modulemd_hash_table_equals (v2_self_1->servicelevels,
230                                    v2_self_2->servicelevels,
231                                    modulemd_service_level_equals_wrapper))
232     {
233       return FALSE;
234     }
235 
236 
237   /* < string, GHashTable <string, Modulemd.RpmMapEntry> > */
238   if (!modulemd_hash_table_equals (
239         v2_self_1->rpm_artifact_map,
240         v2_self_2->rpm_artifact_map,
241         modulemd_RpmMapEntry_hash_table_equals_wrapper))
242     {
243       return FALSE;
244     }
245 
246 
247   if (v2_self_1->dependencies->len != v2_self_2->dependencies->len)
248     {
249       return FALSE;
250     }
251 
252   for (guint i = 0; i < v2_self_1->dependencies->len; i++)
253     {
254       /*Ordering is important for the dependencies,
255        so that each array index must be the same.*/
256       if (!modulemd_dependencies_equals (
257             g_ptr_array_index (v2_self_1->dependencies, i),
258             g_ptr_array_index (v2_self_2->dependencies, i)))
259         {
260           return FALSE;
261         }
262     }
263 
264   if (v2_self_1->xmd == NULL && v2_self_2->xmd == NULL)
265     {
266       return TRUE;
267     }
268 
269   if (v2_self_1->xmd == NULL || v2_self_2->xmd == NULL)
270     {
271       return FALSE;
272     }
273 
274   if (!g_variant_equal (v2_self_1->xmd, v2_self_2->xmd))
275     {
276       return FALSE;
277     }
278 
279   return TRUE;
280 }
281 
282 
283 static guint64
modulemd_module_stream_v2_get_mdversion(ModulemdModuleStream * self)284 modulemd_module_stream_v2_get_mdversion (ModulemdModuleStream *self)
285 {
286   return MD_MODULESTREAM_VERSION_TWO;
287 }
288 
289 
290 void
modulemd_module_stream_v2_set_arch(ModulemdModuleStreamV2 * self,const gchar * arch)291 modulemd_module_stream_v2_set_arch (ModulemdModuleStreamV2 *self,
292                                     const gchar *arch)
293 {
294   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
295 
296   modulemd_module_stream_set_arch (MODULEMD_MODULE_STREAM (self), arch);
297 
298   g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ARCH]);
299 }
300 
301 
302 const gchar *
modulemd_module_stream_v2_get_arch(ModulemdModuleStreamV2 * self)303 modulemd_module_stream_v2_get_arch (ModulemdModuleStreamV2 *self)
304 {
305   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self), NULL);
306 
307   return modulemd_module_stream_get_arch (MODULEMD_MODULE_STREAM (self));
308 }
309 
310 
311 void
modulemd_module_stream_v2_set_buildopts(ModulemdModuleStreamV2 * self,ModulemdBuildopts * buildopts)312 modulemd_module_stream_v2_set_buildopts (ModulemdModuleStreamV2 *self,
313                                          ModulemdBuildopts *buildopts)
314 {
315   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
316 
317   g_clear_object (&self->buildopts);
318   if (buildopts)
319     {
320       self->buildopts = modulemd_buildopts_copy (buildopts);
321     }
322 
323   g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_BUILDOPTS]);
324 }
325 
326 
327 ModulemdBuildopts *
modulemd_module_stream_v2_get_buildopts(ModulemdModuleStreamV2 * self)328 modulemd_module_stream_v2_get_buildopts (ModulemdModuleStreamV2 *self)
329 {
330   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self), NULL);
331 
332   return self->buildopts;
333 }
334 
335 
336 void
modulemd_module_stream_v2_set_community(ModulemdModuleStreamV2 * self,const gchar * community)337 modulemd_module_stream_v2_set_community (ModulemdModuleStreamV2 *self,
338                                          const gchar *community)
339 {
340   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
341 
342   g_clear_pointer (&self->community, g_free);
343   self->community = g_strdup (community);
344 
345   g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_COMMUNITY]);
346 }
347 
348 
349 const gchar *
modulemd_module_stream_v2_get_community(ModulemdModuleStreamV2 * self)350 modulemd_module_stream_v2_get_community (ModulemdModuleStreamV2 *self)
351 {
352   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self), NULL);
353 
354   return self->community;
355 }
356 
357 
358 void
modulemd_module_stream_v2_set_description(ModulemdModuleStreamV2 * self,const gchar * description)359 modulemd_module_stream_v2_set_description (ModulemdModuleStreamV2 *self,
360                                            const gchar *description)
361 {
362   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
363 
364   g_clear_pointer (&self->description, g_free);
365   self->description = g_strdup (description);
366 }
367 
368 
369 const gchar *
modulemd_module_stream_v2_get_description(ModulemdModuleStreamV2 * self,const gchar * locale)370 modulemd_module_stream_v2_get_description (ModulemdModuleStreamV2 *self,
371                                            const gchar *locale)
372 {
373   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self), NULL);
374 
375   ModulemdTranslationEntry *entry =
376     modulemd_module_stream_get_translation_entry (
377       MODULEMD_MODULE_STREAM (self), locale);
378   if (entry != NULL &&
379       modulemd_translation_entry_get_description (entry) != NULL)
380     {
381       return modulemd_translation_entry_get_description (entry);
382     }
383 
384   return self->description;
385 }
386 
387 
388 void
modulemd_module_stream_v2_set_documentation(ModulemdModuleStreamV2 * self,const gchar * documentation)389 modulemd_module_stream_v2_set_documentation (ModulemdModuleStreamV2 *self,
390                                              const gchar *documentation)
391 {
392   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
393 
394   g_clear_pointer (&self->documentation, g_free);
395   self->documentation = g_strdup (documentation);
396 
397   g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_COMMUNITY]);
398 }
399 
400 
401 const gchar *
modulemd_module_stream_v2_get_documentation(ModulemdModuleStreamV2 * self)402 modulemd_module_stream_v2_get_documentation (ModulemdModuleStreamV2 *self)
403 {
404   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self), NULL);
405 
406   return self->documentation;
407 }
408 
409 
410 void
modulemd_module_stream_v2_set_summary(ModulemdModuleStreamV2 * self,const gchar * summary)411 modulemd_module_stream_v2_set_summary (ModulemdModuleStreamV2 *self,
412                                        const gchar *summary)
413 {
414   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
415 
416   g_clear_pointer (&self->summary, g_free);
417   self->summary = g_strdup (summary);
418 }
419 
420 
421 const gchar *
modulemd_module_stream_v2_get_summary(ModulemdModuleStreamV2 * self,const gchar * locale)422 modulemd_module_stream_v2_get_summary (ModulemdModuleStreamV2 *self,
423                                        const gchar *locale)
424 {
425   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self), NULL);
426 
427   ModulemdTranslationEntry *entry =
428     modulemd_module_stream_get_translation_entry (
429       MODULEMD_MODULE_STREAM (self), locale);
430   if (entry != NULL && modulemd_translation_entry_get_summary (entry) != NULL)
431     {
432       return modulemd_translation_entry_get_summary (entry);
433     }
434 
435   return self->summary;
436 }
437 
438 
439 void
modulemd_module_stream_v2_set_tracker(ModulemdModuleStreamV2 * self,const gchar * tracker)440 modulemd_module_stream_v2_set_tracker (ModulemdModuleStreamV2 *self,
441                                        const gchar *tracker)
442 {
443   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
444 
445   g_clear_pointer (&self->tracker, g_free);
446   self->tracker = g_strdup (tracker);
447 
448   g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TRACKER]);
449 }
450 
451 
452 const gchar *
modulemd_module_stream_v2_get_tracker(ModulemdModuleStreamV2 * self)453 modulemd_module_stream_v2_get_tracker (ModulemdModuleStreamV2 *self)
454 {
455   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self), NULL);
456 
457   return self->tracker;
458 }
459 
460 
461 ModulemdObsoletes *
modulemd_module_stream_v2_get_obsoletes_resolved(ModulemdModuleStreamV2 * self)462 modulemd_module_stream_v2_get_obsoletes_resolved (ModulemdModuleStreamV2 *self)
463 {
464   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self), NULL);
465 
466   ModulemdObsoletes *o = self->obsoletes;
467   if (o && modulemd_obsoletes_get_reset (o))
468     {
469       return NULL;
470     }
471 
472   return o;
473 }
474 
475 void
modulemd_module_stream_v2_associate_obsoletes(ModulemdModuleStreamV2 * self,ModulemdObsoletes * obsoletes)476 modulemd_module_stream_v2_associate_obsoletes (ModulemdModuleStreamV2 *self,
477                                                ModulemdObsoletes *obsoletes)
478 {
479   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
480 
481   g_clear_pointer (&self->obsoletes, g_object_unref);
482   if (obsoletes != NULL)
483     {
484       self->obsoletes = g_object_ref (obsoletes);
485     }
486 }
487 
488 ModulemdObsoletes *
modulemd_module_stream_v2_get_obsoletes(ModulemdModuleStreamV2 * self)489 modulemd_module_stream_v2_get_obsoletes (ModulemdModuleStreamV2 *self)
490 {
491   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self), NULL);
492 
493   return self->obsoletes;
494 }
495 
496 
497 /* ===== Non-property Methods ===== */
498 
499 void
modulemd_module_stream_v2_add_component(ModulemdModuleStreamV2 * self,ModulemdComponent * component)500 modulemd_module_stream_v2_add_component (ModulemdModuleStreamV2 *self,
501                                          ModulemdComponent *component)
502 {
503   GHashTable *table = NULL;
504 
505   /* Do nothing if we were passed a NULL component */
506   if (!component)
507     {
508       return;
509     }
510 
511   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
512   g_return_if_fail (MODULEMD_IS_COMPONENT (component));
513 
514   if (MODULEMD_IS_COMPONENT_RPM (component))
515     {
516       table = self->rpm_components;
517     }
518   else if (MODULEMD_IS_COMPONENT_MODULE (component))
519     {
520       table = self->module_components;
521     }
522   else
523     {
524       /* Unknown component. Raise a warning and return */
525       g_return_if_reached ();
526     }
527 
528   /* Add the component to the table. This will replace an existing component
529    * with the same name
530    */
531   g_hash_table_replace (table,
532                         g_strdup (modulemd_component_get_key (component)),
533                         modulemd_component_copy (component, NULL));
534 }
535 
536 
537 void
modulemd_module_stream_v2_remove_module_component(ModulemdModuleStreamV2 * self,const gchar * component_name)538 modulemd_module_stream_v2_remove_module_component (
539   ModulemdModuleStreamV2 *self, const gchar *component_name)
540 {
541   /* Do nothing if we were passed a NULL component_name */
542   if (!component_name)
543     {
544       return;
545     }
546 
547   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
548 
549   g_hash_table_remove (self->module_components, component_name);
550 }
551 
552 
553 void
modulemd_module_stream_v2_clear_module_components(ModulemdModuleStreamV2 * self)554 modulemd_module_stream_v2_clear_module_components (
555   ModulemdModuleStreamV2 *self)
556 {
557   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
558 
559   g_hash_table_remove_all (self->module_components);
560 }
561 
562 
563 void
modulemd_module_stream_v2_remove_rpm_component(ModulemdModuleStreamV2 * self,const gchar * component_name)564 modulemd_module_stream_v2_remove_rpm_component (ModulemdModuleStreamV2 *self,
565                                                 const gchar *component_name)
566 {
567   /* Do nothing if we were passed a NULL component_name */
568   if (!component_name)
569     {
570       return;
571     }
572 
573   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
574 
575   g_hash_table_remove (self->rpm_components, component_name);
576 }
577 
578 
579 void
modulemd_module_stream_v2_clear_rpm_components(ModulemdModuleStreamV2 * self)580 modulemd_module_stream_v2_clear_rpm_components (ModulemdModuleStreamV2 *self)
581 {
582   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
583 
584   g_hash_table_remove_all (self->rpm_components);
585 }
586 
587 
588 GStrv
modulemd_module_stream_v2_get_module_component_names_as_strv(ModulemdModuleStreamV2 * self)589 modulemd_module_stream_v2_get_module_component_names_as_strv (
590   ModulemdModuleStreamV2 *self)
591 {
592   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self), NULL);
593 
594   return modulemd_ordered_str_keys_as_strv (self->module_components);
595 }
596 
597 
598 GStrv
modulemd_module_stream_v2_get_rpm_component_names_as_strv(ModulemdModuleStreamV2 * self)599 modulemd_module_stream_v2_get_rpm_component_names_as_strv (
600   ModulemdModuleStreamV2 *self)
601 {
602   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self), NULL);
603 
604   return modulemd_ordered_str_keys_as_strv (self->rpm_components);
605 }
606 
607 
608 ModulemdComponentModule *
modulemd_module_stream_v2_get_module_component(ModulemdModuleStreamV2 * self,const gchar * component_name)609 modulemd_module_stream_v2_get_module_component (ModulemdModuleStreamV2 *self,
610                                                 const gchar *component_name)
611 {
612   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self), NULL);
613 
614   return g_hash_table_lookup (self->module_components, component_name);
615 }
616 
617 
618 ModulemdComponentRpm *
modulemd_module_stream_v2_get_rpm_component(ModulemdModuleStreamV2 * self,const gchar * component_name)619 modulemd_module_stream_v2_get_rpm_component (ModulemdModuleStreamV2 *self,
620                                              const gchar *component_name)
621 {
622   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self), NULL);
623 
624   return g_hash_table_lookup (self->rpm_components, component_name);
625 }
626 
627 
628 void
modulemd_module_stream_v2_add_content_license(ModulemdModuleStreamV2 * self,const gchar * license)629 modulemd_module_stream_v2_add_content_license (ModulemdModuleStreamV2 *self,
630                                                const gchar *license)
631 {
632   if (!license)
633     {
634       return;
635     }
636 
637   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
638 
639   g_hash_table_add (self->content_licenses, g_strdup (license));
640 }
641 
642 
643 void
modulemd_module_stream_v2_replace_content_licenses(ModulemdModuleStreamV2 * self,GHashTable * set)644 modulemd_module_stream_v2_replace_content_licenses (
645   ModulemdModuleStreamV2 *self, GHashTable *set)
646 {
647   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
648 
649   MODULEMD_REPLACE_SET (self->content_licenses, set);
650 }
651 
652 
653 void
modulemd_module_stream_v2_add_module_license(ModulemdModuleStreamV2 * self,const gchar * license)654 modulemd_module_stream_v2_add_module_license (ModulemdModuleStreamV2 *self,
655                                               const gchar *license)
656 {
657   if (!license)
658     {
659       return;
660     }
661 
662   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
663 
664   g_hash_table_add (self->module_licenses, g_strdup (license));
665 }
666 
667 
668 void
modulemd_module_stream_v2_replace_module_licenses(ModulemdModuleStreamV2 * self,GHashTable * set)669 modulemd_module_stream_v2_replace_module_licenses (
670   ModulemdModuleStreamV2 *self, GHashTable *set)
671 {
672   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
673 
674   MODULEMD_REPLACE_SET (self->module_licenses, set);
675 }
676 
677 
678 void
modulemd_module_stream_v2_remove_content_license(ModulemdModuleStreamV2 * self,const gchar * license)679 modulemd_module_stream_v2_remove_content_license (ModulemdModuleStreamV2 *self,
680                                                   const gchar *license)
681 {
682   if (!license)
683     {
684       return;
685     }
686 
687   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
688 
689   g_hash_table_remove (self->content_licenses, license);
690 }
691 
692 
693 void
modulemd_module_stream_v2_remove_module_license(ModulemdModuleStreamV2 * self,const gchar * license)694 modulemd_module_stream_v2_remove_module_license (ModulemdModuleStreamV2 *self,
695                                                  const gchar *license)
696 {
697   if (!license)
698     {
699       return;
700     }
701 
702   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
703 
704   g_hash_table_remove (self->module_licenses, license);
705 }
706 
707 
708 void
modulemd_module_stream_v2_clear_content_licenses(ModulemdModuleStreamV2 * self)709 modulemd_module_stream_v2_clear_content_licenses (ModulemdModuleStreamV2 *self)
710 {
711   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
712 
713   g_hash_table_remove_all (self->content_licenses);
714 }
715 
716 
717 void
modulemd_module_stream_v2_clear_module_licenses(ModulemdModuleStreamV2 * self)718 modulemd_module_stream_v2_clear_module_licenses (ModulemdModuleStreamV2 *self)
719 {
720   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
721 
722   g_hash_table_remove_all (self->module_licenses);
723 }
724 
725 
726 GStrv
modulemd_module_stream_v2_get_content_licenses_as_strv(ModulemdModuleStreamV2 * self)727 modulemd_module_stream_v2_get_content_licenses_as_strv (
728   ModulemdModuleStreamV2 *self)
729 {
730   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self), NULL);
731 
732   return modulemd_ordered_str_keys_as_strv (self->content_licenses);
733 }
734 
735 
736 GStrv
modulemd_module_stream_v2_get_module_licenses_as_strv(ModulemdModuleStreamV2 * self)737 modulemd_module_stream_v2_get_module_licenses_as_strv (
738   ModulemdModuleStreamV2 *self)
739 {
740   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self), NULL);
741 
742   return modulemd_ordered_str_keys_as_strv (self->module_licenses);
743 }
744 
745 
746 void
modulemd_module_stream_v2_add_profile(ModulemdModuleStreamV2 * self,ModulemdProfile * profile)747 modulemd_module_stream_v2_add_profile (ModulemdModuleStreamV2 *self,
748                                        ModulemdProfile *profile)
749 {
750   if (!profile)
751     {
752       return;
753     }
754   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
755   g_return_if_fail (MODULEMD_IS_PROFILE (profile));
756 
757   ModulemdProfile *copied_profile = modulemd_profile_copy (profile);
758   modulemd_profile_set_owner (copied_profile, MODULEMD_MODULE_STREAM (self));
759 
760   g_hash_table_replace (self->profiles,
761                         g_strdup (modulemd_profile_get_name (profile)),
762                         copied_profile);
763 }
764 
765 
766 void
modulemd_module_stream_v2_clear_profiles(ModulemdModuleStreamV2 * self)767 modulemd_module_stream_v2_clear_profiles (ModulemdModuleStreamV2 *self)
768 {
769   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
770 
771   g_hash_table_remove_all (self->profiles);
772 }
773 
774 
775 GStrv
modulemd_module_stream_v2_get_profile_names_as_strv(ModulemdModuleStreamV2 * self)776 modulemd_module_stream_v2_get_profile_names_as_strv (
777   ModulemdModuleStreamV2 *self)
778 {
779   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self), NULL);
780 
781   return modulemd_ordered_str_keys_as_strv (self->profiles);
782 }
783 
784 
785 ModulemdProfile *
modulemd_module_stream_v2_get_profile(ModulemdModuleStreamV2 * self,const gchar * profile_name)786 modulemd_module_stream_v2_get_profile (ModulemdModuleStreamV2 *self,
787                                        const gchar *profile_name)
788 {
789   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self), NULL);
790 
791   return g_hash_table_lookup (self->profiles, profile_name);
792 }
793 
794 
795 struct profile_match_ctx
796 {
797   GHashTable *profiles;
798   GPtrArray *found;
799   const gchar *pattern;
800 };
801 
802 static void
profile_match(gpointer data,gpointer user_data)803 profile_match (gpointer data, gpointer user_data)
804 {
805   struct profile_match_ctx *match_ctx = (struct profile_match_ctx *)user_data;
806 
807   /* Add it to the found list if it matches the pattern */
808   if (modulemd_fnmatch (match_ctx->pattern, (const gchar *)data))
809     {
810       g_ptr_array_add (match_ctx->found,
811                        g_object_ref (g_hash_table_lookup (
812                          match_ctx->profiles, (const gchar *)data)));
813     }
814 }
815 
816 GPtrArray *
modulemd_module_stream_v2_search_profiles(ModulemdModuleStreamV2 * self,const gchar * profile_pattern)817 modulemd_module_stream_v2_search_profiles (ModulemdModuleStreamV2 *self,
818                                            const gchar *profile_pattern)
819 {
820   /* The list of profiles will probably never be large, so we'll optimize for
821    * the worst-case and preallocate the array to the number of profiles.
822    */
823   GPtrArray *found =
824     g_ptr_array_new_full (g_hash_table_size (self->profiles), g_object_unref);
825 
826   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self), found);
827 
828   g_autoptr (GPtrArray) profile_names =
829     modulemd_ordered_str_keys (self->profiles, modulemd_strcmp_sort);
830 
831   struct profile_match_ctx match_ctx = { .profiles = self->profiles,
832                                          .found = found,
833                                          .pattern = profile_pattern };
834 
835   g_ptr_array_foreach (profile_names, profile_match, &match_ctx);
836 
837   return found;
838 }
839 
840 
841 void
modulemd_module_stream_v2_add_rpm_api(ModulemdModuleStreamV2 * self,const gchar * rpm)842 modulemd_module_stream_v2_add_rpm_api (ModulemdModuleStreamV2 *self,
843                                        const gchar *rpm)
844 {
845   if (!rpm)
846     {
847       return;
848     }
849 
850   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
851 
852   g_hash_table_add (self->rpm_api, g_strdup (rpm));
853 }
854 
855 
856 void
modulemd_module_stream_v2_replace_rpm_api(ModulemdModuleStreamV2 * self,GHashTable * set)857 modulemd_module_stream_v2_replace_rpm_api (ModulemdModuleStreamV2 *self,
858                                            GHashTable *set)
859 {
860   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
861 
862   MODULEMD_REPLACE_SET (self->rpm_api, set);
863 }
864 
865 
866 void
modulemd_module_stream_v2_remove_rpm_api(ModulemdModuleStreamV2 * self,const gchar * rpm)867 modulemd_module_stream_v2_remove_rpm_api (ModulemdModuleStreamV2 *self,
868                                           const gchar *rpm)
869 {
870   if (!rpm)
871     {
872       return;
873     }
874 
875   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
876 
877   g_hash_table_remove (self->rpm_api, rpm);
878 }
879 
880 
881 void
modulemd_module_stream_v2_clear_rpm_api(ModulemdModuleStreamV2 * self)882 modulemd_module_stream_v2_clear_rpm_api (ModulemdModuleStreamV2 *self)
883 {
884   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
885 
886   g_hash_table_remove_all (self->rpm_api);
887 }
888 
889 
890 GStrv
modulemd_module_stream_v2_get_rpm_api_as_strv(ModulemdModuleStreamV2 * self)891 modulemd_module_stream_v2_get_rpm_api_as_strv (ModulemdModuleStreamV2 *self)
892 {
893   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self), NULL);
894 
895   return modulemd_ordered_str_keys_as_strv (self->rpm_api);
896 }
897 
898 
899 void
modulemd_module_stream_v2_add_rpm_artifact(ModulemdModuleStreamV2 * self,const gchar * nevr)900 modulemd_module_stream_v2_add_rpm_artifact (ModulemdModuleStreamV2 *self,
901                                             const gchar *nevr)
902 {
903   if (!nevr)
904     {
905       return;
906     }
907 
908   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
909 
910   g_hash_table_add (self->rpm_artifacts, g_strdup (nevr));
911 }
912 
913 
914 void
modulemd_module_stream_v2_replace_rpm_artifacts(ModulemdModuleStreamV2 * self,GHashTable * set)915 modulemd_module_stream_v2_replace_rpm_artifacts (ModulemdModuleStreamV2 *self,
916                                                  GHashTable *set)
917 {
918   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
919 
920   MODULEMD_REPLACE_SET (self->rpm_artifacts, set);
921 }
922 
923 
924 void
modulemd_module_stream_v2_remove_rpm_artifact(ModulemdModuleStreamV2 * self,const gchar * nevr)925 modulemd_module_stream_v2_remove_rpm_artifact (ModulemdModuleStreamV2 *self,
926                                                const gchar *nevr)
927 {
928   if (!nevr)
929     {
930       return;
931     }
932 
933   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
934 
935   g_hash_table_remove (self->rpm_artifacts, nevr);
936 }
937 
938 
939 void
modulemd_module_stream_v2_clear_rpm_artifacts(ModulemdModuleStreamV2 * self)940 modulemd_module_stream_v2_clear_rpm_artifacts (ModulemdModuleStreamV2 *self)
941 {
942   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
943 
944   g_hash_table_remove_all (self->rpm_artifacts);
945 }
946 
947 
948 GStrv
modulemd_module_stream_v2_get_rpm_artifacts_as_strv(ModulemdModuleStreamV2 * self)949 modulemd_module_stream_v2_get_rpm_artifacts_as_strv (
950   ModulemdModuleStreamV2 *self)
951 {
952   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self), NULL);
953 
954   return modulemd_ordered_str_keys_as_strv (self->rpm_artifacts);
955 }
956 
957 
958 static GHashTable *
get_or_create_digest_table(ModulemdModuleStreamV2 * self,const gchar * digest)959 get_or_create_digest_table (ModulemdModuleStreamV2 *self, const gchar *digest)
960 {
961   GHashTable *digest_table =
962     g_hash_table_lookup (self->rpm_artifact_map, digest);
963   if (digest_table == NULL)
964     {
965       digest_table = g_hash_table_new_full (
966         g_str_hash, g_str_equal, g_free, g_object_unref);
967       g_hash_table_insert (
968         self->rpm_artifact_map, g_strdup (digest), digest_table);
969     }
970 
971   return digest_table;
972 }
973 
974 
975 void
modulemd_module_stream_v2_set_rpm_artifact_map_entry(ModulemdModuleStreamV2 * self,ModulemdRpmMapEntry * entry,const gchar * digest,const gchar * checksum)976 modulemd_module_stream_v2_set_rpm_artifact_map_entry (
977   ModulemdModuleStreamV2 *self,
978   ModulemdRpmMapEntry *entry,
979   const gchar *digest,
980   const gchar *checksum)
981 {
982   GHashTable *digest_table = NULL;
983 
984   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
985   g_return_if_fail (entry && digest && checksum);
986 
987   digest_table = get_or_create_digest_table (self, digest);
988 
989   g_hash_table_insert (
990     digest_table, g_strdup (checksum), modulemd_rpm_map_entry_copy (entry));
991 }
992 
993 
994 ModulemdRpmMapEntry *
modulemd_module_stream_v2_get_rpm_artifact_map_entry(ModulemdModuleStreamV2 * self,const gchar * digest,const gchar * checksum)995 modulemd_module_stream_v2_get_rpm_artifact_map_entry (
996   ModulemdModuleStreamV2 *self, const gchar *digest, const gchar *checksum)
997 {
998   GHashTable *digest_table = NULL;
999   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self), NULL);
1000   g_return_val_if_fail (digest && checksum, NULL);
1001 
1002   digest_table = g_hash_table_lookup (self->rpm_artifact_map, digest);
1003   if (!digest_table)
1004     {
1005       return NULL;
1006     }
1007 
1008   return g_hash_table_lookup (digest_table, checksum);
1009 }
1010 
1011 
1012 void
modulemd_module_stream_v2_add_rpm_filter(ModulemdModuleStreamV2 * self,const gchar * rpm)1013 modulemd_module_stream_v2_add_rpm_filter (ModulemdModuleStreamV2 *self,
1014                                           const gchar *rpm)
1015 {
1016   if (!rpm)
1017     {
1018       return;
1019     }
1020 
1021   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
1022 
1023   g_hash_table_add (self->rpm_filters, g_strdup (rpm));
1024 }
1025 
1026 
1027 void
modulemd_module_stream_v2_replace_rpm_filters(ModulemdModuleStreamV2 * self,GHashTable * set)1028 modulemd_module_stream_v2_replace_rpm_filters (ModulemdModuleStreamV2 *self,
1029                                                GHashTable *set)
1030 {
1031   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
1032 
1033   MODULEMD_REPLACE_SET (self->rpm_filters, set);
1034 }
1035 
1036 
1037 void
modulemd_module_stream_v2_remove_rpm_filter(ModulemdModuleStreamV2 * self,const gchar * rpm)1038 modulemd_module_stream_v2_remove_rpm_filter (ModulemdModuleStreamV2 *self,
1039                                              const gchar *rpm)
1040 {
1041   if (!rpm)
1042     {
1043       return;
1044     }
1045 
1046   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
1047 
1048   g_hash_table_remove (self->rpm_filters, rpm);
1049 }
1050 
1051 
1052 void
modulemd_module_stream_v2_clear_rpm_filters(ModulemdModuleStreamV2 * self)1053 modulemd_module_stream_v2_clear_rpm_filters (ModulemdModuleStreamV2 *self)
1054 {
1055   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
1056 
1057   g_hash_table_remove_all (self->rpm_filters);
1058 }
1059 
1060 
1061 GStrv
modulemd_module_stream_v2_get_rpm_filters_as_strv(ModulemdModuleStreamV2 * self)1062 modulemd_module_stream_v2_get_rpm_filters_as_strv (
1063   ModulemdModuleStreamV2 *self)
1064 {
1065   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self), NULL);
1066 
1067   return modulemd_ordered_str_keys_as_strv (self->rpm_filters);
1068 }
1069 
1070 
1071 void
modulemd_module_stream_v2_add_demodularized_rpm(ModulemdModuleStreamV2 * self,const gchar * rpm)1072 modulemd_module_stream_v2_add_demodularized_rpm (ModulemdModuleStreamV2 *self,
1073                                                  const gchar *rpm)
1074 {
1075   if (!rpm)
1076     {
1077       return;
1078     }
1079 
1080   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
1081 
1082   g_hash_table_add (self->demodularized_rpms, g_strdup (rpm));
1083 }
1084 
1085 
1086 void
modulemd_module_stream_v2_replace_demodularized_rpms(ModulemdModuleStreamV2 * self,GHashTable * set)1087 modulemd_module_stream_v2_replace_demodularized_rpms (
1088   ModulemdModuleStreamV2 *self, GHashTable *set)
1089 {
1090   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
1091 
1092   MODULEMD_REPLACE_SET (self->demodularized_rpms, set);
1093 }
1094 
1095 
1096 void
modulemd_module_stream_v2_remove_demodularized_rpm(ModulemdModuleStreamV2 * self,const gchar * rpm)1097 modulemd_module_stream_v2_remove_demodularized_rpm (
1098   ModulemdModuleStreamV2 *self, const gchar *rpm)
1099 {
1100   if (!rpm)
1101     {
1102       return;
1103     }
1104 
1105   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
1106 
1107   g_hash_table_remove (self->demodularized_rpms, rpm);
1108 }
1109 
1110 
1111 void
modulemd_module_stream_v2_clear_demodularized_rpms(ModulemdModuleStreamV2 * self)1112 modulemd_module_stream_v2_clear_demodularized_rpms (
1113   ModulemdModuleStreamV2 *self)
1114 {
1115   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
1116 
1117   g_hash_table_remove_all (self->demodularized_rpms);
1118 }
1119 
1120 
1121 GStrv
modulemd_module_stream_v2_get_demodularized_rpms(ModulemdModuleStreamV2 * self)1122 modulemd_module_stream_v2_get_demodularized_rpms (ModulemdModuleStreamV2 *self)
1123 {
1124   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self), NULL);
1125 
1126   return modulemd_ordered_str_keys_as_strv (self->demodularized_rpms);
1127 }
1128 
1129 
1130 void
modulemd_module_stream_v2_add_servicelevel(ModulemdModuleStreamV2 * self,ModulemdServiceLevel * servicelevel)1131 modulemd_module_stream_v2_add_servicelevel (ModulemdModuleStreamV2 *self,
1132                                             ModulemdServiceLevel *servicelevel)
1133 {
1134   if (!servicelevel)
1135     {
1136       return;
1137     }
1138   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
1139   g_return_if_fail (MODULEMD_IS_SERVICE_LEVEL (servicelevel));
1140 
1141   g_hash_table_replace (
1142     self->servicelevels,
1143     g_strdup (modulemd_service_level_get_name (servicelevel)),
1144     modulemd_service_level_copy (servicelevel));
1145 }
1146 
1147 
1148 void
modulemd_module_stream_v2_clear_servicelevels(ModulemdModuleStreamV2 * self)1149 modulemd_module_stream_v2_clear_servicelevels (ModulemdModuleStreamV2 *self)
1150 {
1151   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
1152 
1153   g_hash_table_remove_all (self->servicelevels);
1154 }
1155 
1156 
1157 GStrv
modulemd_module_stream_v2_get_servicelevel_names_as_strv(ModulemdModuleStreamV2 * self)1158 modulemd_module_stream_v2_get_servicelevel_names_as_strv (
1159   ModulemdModuleStreamV2 *self)
1160 {
1161   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self), NULL);
1162 
1163   return modulemd_ordered_str_keys_as_strv (self->servicelevels);
1164 }
1165 
1166 
1167 ModulemdServiceLevel *
modulemd_module_stream_v2_get_servicelevel(ModulemdModuleStreamV2 * self,const gchar * servicelevel_name)1168 modulemd_module_stream_v2_get_servicelevel (ModulemdModuleStreamV2 *self,
1169                                             const gchar *servicelevel_name)
1170 {
1171   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self), NULL);
1172 
1173   return g_hash_table_lookup (self->servicelevels, servicelevel_name);
1174 }
1175 
1176 
1177 void
modulemd_module_stream_v2_add_dependencies(ModulemdModuleStreamV2 * self,ModulemdDependencies * deps)1178 modulemd_module_stream_v2_add_dependencies (ModulemdModuleStreamV2 *self,
1179                                             ModulemdDependencies *deps)
1180 {
1181   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
1182 
1183   g_ptr_array_add (self->dependencies, modulemd_dependencies_copy (deps));
1184 }
1185 
1186 
1187 void
modulemd_module_stream_v2_replace_dependencies(ModulemdModuleStreamV2 * self,GPtrArray * array)1188 modulemd_module_stream_v2_replace_dependencies (ModulemdModuleStreamV2 *self,
1189                                                 GPtrArray *array)
1190 {
1191   gsize i;
1192   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
1193 
1194   for (i = 0; i < array->len; i++)
1195     {
1196       modulemd_module_stream_v2_add_dependencies (
1197         self, g_ptr_array_index (array, i));
1198     }
1199 }
1200 
1201 
1202 void
modulemd_module_stream_v2_clear_dependencies(ModulemdModuleStreamV2 * self)1203 modulemd_module_stream_v2_clear_dependencies (ModulemdModuleStreamV2 *self)
1204 {
1205   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
1206 
1207   g_ptr_array_set_size (self->dependencies, 0);
1208 }
1209 
1210 
1211 static gboolean
dep_equal_wrapper(gconstpointer a,gconstpointer b)1212 dep_equal_wrapper (gconstpointer a, gconstpointer b)
1213 {
1214   return modulemd_dependencies_equals ((ModulemdDependencies *)a,
1215                                        (ModulemdDependencies *)b);
1216 }
1217 
1218 
1219 void
modulemd_module_stream_v2_remove_dependencies(ModulemdModuleStreamV2 * self,ModulemdDependencies * deps)1220 modulemd_module_stream_v2_remove_dependencies (ModulemdModuleStreamV2 *self,
1221                                                ModulemdDependencies *deps)
1222 {
1223   guint index;
1224   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
1225 
1226   while (g_ptr_array_find_with_equal_func (
1227     self->dependencies, deps, dep_equal_wrapper, &index))
1228     {
1229       g_ptr_array_remove_index (self->dependencies, index);
1230     }
1231 }
1232 
1233 
1234 GPtrArray *
modulemd_module_stream_v2_get_dependencies(ModulemdModuleStreamV2 * self)1235 modulemd_module_stream_v2_get_dependencies (ModulemdModuleStreamV2 *self)
1236 {
1237   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self), NULL);
1238 
1239   return self->dependencies;
1240 }
1241 
1242 
1243 void
modulemd_module_stream_v2_set_xmd(ModulemdModuleStreamV2 * self,GVariant * xmd)1244 modulemd_module_stream_v2_set_xmd (ModulemdModuleStreamV2 *self, GVariant *xmd)
1245 {
1246   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self));
1247 
1248   /* Do nothing if we were passed the same pointer */
1249   if (self->xmd == xmd)
1250     {
1251       return;
1252     }
1253 
1254   g_clear_pointer (&self->xmd, g_variant_unref);
1255   self->xmd = modulemd_variant_deep_copy (xmd);
1256 }
1257 
1258 GVariant *
modulemd_module_stream_v2_get_xmd(ModulemdModuleStreamV2 * self)1259 modulemd_module_stream_v2_get_xmd (ModulemdModuleStreamV2 *self)
1260 {
1261   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self), NULL);
1262   return self->xmd;
1263 }
1264 
1265 
1266 gboolean
modulemd_module_stream_v2_includes_nevra(ModulemdModuleStreamV2 * self,const gchar * nevra_pattern)1267 modulemd_module_stream_v2_includes_nevra (ModulemdModuleStreamV2 *self,
1268                                           const gchar *nevra_pattern)
1269 {
1270   /* If g_hash_table_find() returns non-NULL, the nevra was found in this
1271    * module stream, so return TRUE
1272    */
1273   return !!g_hash_table_find (
1274     self->rpm_artifacts, modulemd_rpm_match, (void *)nevra_pattern);
1275 }
1276 
1277 
1278 void
modulemd_module_stream_v2_set_static_context(ModulemdModuleStreamV2 * self)1279 modulemd_module_stream_v2_set_static_context (ModulemdModuleStreamV2 *self)
1280 {
1281   self->static_context = TRUE;
1282 
1283   g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_STATIC_CONTEXT]);
1284 }
1285 
1286 
1287 void
modulemd_module_stream_v2_unset_static_context(ModulemdModuleStreamV2 * self)1288 modulemd_module_stream_v2_unset_static_context (ModulemdModuleStreamV2 *self)
1289 {
1290   self->static_context = FALSE;
1291 
1292   g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_STATIC_CONTEXT]);
1293 }
1294 
1295 
1296 gboolean
modulemd_module_stream_v2_is_static_context(ModulemdModuleStreamV2 * self)1297 modulemd_module_stream_v2_is_static_context (ModulemdModuleStreamV2 *self)
1298 {
1299   return self->static_context;
1300 }
1301 
1302 
1303 static gboolean
modulemd_module_stream_v2_validate_context(const gchar * context,GError ** error)1304 modulemd_module_stream_v2_validate_context (const gchar *context,
1305                                             GError **error)
1306 {
1307   /* must be string of up to MODULEMD_MODULE_STREAM_V2_MAXCONTEXTLEN [a-zA-Z0-9_] */
1308 
1309   if (context == NULL || *context == '\0')
1310     {
1311       g_set_error (
1312         error, MODULEMD_ERROR, MMD_ERROR_VALIDATE, "Empty stream context");
1313       return FALSE;
1314     }
1315 
1316   if (strlen (context) > MODULEMD_MODULE_STREAM_V2_MAXCONTEXTLEN)
1317     {
1318       g_set_error (error,
1319                    MODULEMD_ERROR,
1320                    MMD_ERROR_VALIDATE,
1321                    "Stream context '%s' exceeds maximum length (%d)",
1322                    context,
1323                    MODULEMD_MODULE_STREAM_V2_MAXCONTEXTLEN);
1324       return FALSE;
1325     }
1326 
1327   for (const gchar *i = context; *i != '\0'; i++)
1328     {
1329       if (!g_ascii_isalnum (*i) && *i != '_')
1330         {
1331           g_set_error (
1332             error,
1333             MODULEMD_ERROR,
1334             MMD_ERROR_VALIDATE,
1335             "Stream context '%s' can only contain [a-zA-Z0-9_] characters",
1336             context);
1337           return FALSE;
1338         }
1339     }
1340 
1341   return TRUE;
1342 }
1343 
1344 
1345 static gboolean
modulemd_module_stream_v2_validate(ModulemdModuleStream * self,GError ** error)1346 modulemd_module_stream_v2_validate (ModulemdModuleStream *self, GError **error)
1347 {
1348   GHashTableIter iter;
1349   gpointer key;
1350   gpointer value;
1351   gchar *nevra = NULL;
1352   ModulemdModuleStreamV2 *v2_self = NULL;
1353   ModulemdDependencies *deps = NULL;
1354   g_autoptr (GError) nested_error = NULL;
1355   g_auto (GStrv) buildopts_arches = NULL;
1356   const gchar *context = NULL;
1357 
1358   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self), FALSE);
1359   v2_self = MODULEMD_MODULE_STREAM_V2 (self);
1360 
1361   if (!MODULEMD_MODULE_STREAM_CLASS (modulemd_module_stream_v2_parent_class)
1362          ->validate (self, error))
1363     {
1364       return FALSE;
1365     }
1366 
1367   /* Validate static context if present */
1368   if (v2_self->static_context)
1369     {
1370       context =
1371         modulemd_module_stream_get_context (MODULEMD_MODULE_STREAM (self));
1372       if (context)
1373         {
1374           if (!modulemd_module_stream_v2_validate_context (context,
1375                                                            &nested_error))
1376             {
1377               g_propagate_error (error, g_steal_pointer (&nested_error));
1378               return FALSE;
1379             }
1380         }
1381     }
1382 
1383   /* Make sure that mandatory fields are present */
1384   if (!modulemd_module_stream_v2_get_summary (v2_self, "C"))
1385     {
1386       g_set_error (error,
1387                    MODULEMD_YAML_ERROR,
1388                    MMD_YAML_ERROR_MISSING_REQUIRED,
1389                    "Summary is missing");
1390       return FALSE;
1391     }
1392 
1393   if (!modulemd_module_stream_v2_get_description (v2_self, "C"))
1394     {
1395       g_set_error (error,
1396                    MODULEMD_YAML_ERROR,
1397                    MMD_YAML_ERROR_MISSING_REQUIRED,
1398                    "Description is missing");
1399       return FALSE;
1400     }
1401 
1402   if (!g_hash_table_size (v2_self->module_licenses))
1403     {
1404       g_set_error (error,
1405                    MODULEMD_YAML_ERROR,
1406                    MMD_YAML_ERROR_MISSING_REQUIRED,
1407                    "Module license is missing");
1408       return FALSE;
1409     }
1410 
1411   /* Verify that the components are consistent with regards to buildorder and
1412    * buildafter values.
1413    */
1414   if (!modulemd_module_stream_validate_components (v2_self->rpm_components,
1415                                                    &nested_error))
1416     {
1417       g_propagate_error (error, g_steal_pointer (&nested_error));
1418       return FALSE;
1419     }
1420 
1421   if (v2_self->buildopts != NULL)
1422     {
1423       /* Verify that the component rpm arches are consistent with any module
1424        * level arches.
1425        */
1426       buildopts_arches =
1427         modulemd_buildopts_get_arches_as_strv (v2_self->buildopts);
1428       if (!modulemd_module_stream_validate_component_rpm_arches (
1429             v2_self->rpm_components, buildopts_arches, &nested_error))
1430         {
1431           g_propagate_error (error, g_steal_pointer (&nested_error));
1432           return FALSE;
1433         }
1434     }
1435 
1436   /* Iterate through the artifacts and validate that they are in the proper
1437    * NEVRA format
1438    */
1439   g_hash_table_iter_init (&iter, v2_self->rpm_artifacts);
1440   while (g_hash_table_iter_next (&iter, &key, &value))
1441     {
1442       nevra = (gchar *)key;
1443       if (!modulemd_validate_nevra (nevra))
1444         {
1445           g_set_error (error,
1446                        MODULEMD_ERROR,
1447                        MMD_ERROR_VALIDATE,
1448                        "Artifact '%s' was not in valid N-E:V-R.A format.",
1449                        nevra);
1450           return FALSE;
1451         }
1452     }
1453 
1454   /* Iterate through the Dependencies and validate them */
1455   for (guint i = 0; i < v2_self->dependencies->len; i++)
1456     {
1457       deps =
1458         MODULEMD_DEPENDENCIES (g_ptr_array_index (v2_self->dependencies, i));
1459       if (!modulemd_dependencies_validate (deps, &nested_error))
1460         {
1461           g_propagate_prefixed_error (error,
1462                                       g_steal_pointer (&nested_error),
1463                                       "Dependency failed to validate: ");
1464           return FALSE;
1465         }
1466     }
1467 
1468   return TRUE;
1469 }
1470 
1471 
1472 static void
modulemd_module_stream_v2_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1473 modulemd_module_stream_v2_get_property (GObject *object,
1474                                         guint prop_id,
1475                                         GValue *value,
1476                                         GParamSpec *pspec)
1477 {
1478   ModulemdModuleStreamV2 *self = MODULEMD_MODULE_STREAM_V2 (object);
1479 
1480   switch (prop_id)
1481     {
1482     case PROP_ARCH:
1483       g_value_set_string (value, modulemd_module_stream_v2_get_arch (self));
1484       break;
1485 
1486     case PROP_BUILDOPTS:
1487       g_value_set_object (value,
1488                           modulemd_module_stream_v2_get_buildopts (self));
1489       break;
1490 
1491     case PROP_COMMUNITY:
1492       g_value_set_string (value,
1493                           modulemd_module_stream_v2_get_community (self));
1494       break;
1495 
1496     case PROP_DOCUMENTATION:
1497       g_value_set_string (value,
1498                           modulemd_module_stream_v2_get_documentation (self));
1499       break;
1500 
1501     case PROP_TRACKER:
1502       g_value_set_string (value, modulemd_module_stream_v2_get_tracker (self));
1503       break;
1504 
1505     case PROP_STATIC_CONTEXT:
1506       g_value_set_boolean (value,
1507                            modulemd_module_stream_v2_is_static_context (self));
1508       break;
1509 
1510     default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1511     }
1512 }
1513 
1514 static void
modulemd_module_stream_v2_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1515 modulemd_module_stream_v2_set_property (GObject *object,
1516                                         guint prop_id,
1517                                         const GValue *value,
1518                                         GParamSpec *pspec)
1519 {
1520   ModulemdModuleStreamV2 *self = MODULEMD_MODULE_STREAM_V2 (object);
1521   switch (prop_id)
1522     {
1523     case PROP_ARCH:
1524       modulemd_module_stream_v2_set_arch (self, g_value_get_string (value));
1525       break;
1526 
1527     case PROP_BUILDOPTS:
1528       modulemd_module_stream_v2_set_buildopts (self,
1529                                                g_value_get_object (value));
1530       break;
1531 
1532     case PROP_COMMUNITY:
1533       modulemd_module_stream_v2_set_community (self,
1534                                                g_value_get_string (value));
1535       break;
1536 
1537     case PROP_DOCUMENTATION:
1538       modulemd_module_stream_v2_set_documentation (self,
1539                                                    g_value_get_string (value));
1540       break;
1541 
1542     case PROP_TRACKER:
1543       modulemd_module_stream_v2_set_tracker (self, g_value_get_string (value));
1544       break;
1545 
1546     case PROP_STATIC_CONTEXT:
1547       if (g_value_get_boolean (value))
1548         {
1549           modulemd_module_stream_v2_set_static_context (self);
1550         }
1551       else
1552         {
1553           modulemd_module_stream_v2_unset_static_context (self);
1554         }
1555       break;
1556 
1557     default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1558     }
1559 }
1560 
1561 static void
copy_rpm_artifact_map(ModulemdModuleStreamV2 * from,ModulemdModuleStreamV2 * to)1562 copy_rpm_artifact_map (ModulemdModuleStreamV2 *from,
1563                        ModulemdModuleStreamV2 *to)
1564 {
1565   GHashTableIter outer;
1566   GHashTableIter inner;
1567   gpointer outer_key;
1568   gpointer outer_value;
1569   gpointer inner_key;
1570   gpointer inner_value;
1571   GHashTable *to_digest_table = NULL;
1572 
1573   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (from));
1574   g_return_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (to));
1575 
1576   g_hash_table_iter_init (&outer, from->rpm_artifact_map);
1577   while (g_hash_table_iter_next (&outer, &outer_key, &outer_value))
1578     {
1579       to_digest_table = get_or_create_digest_table (to, outer_key);
1580 
1581       g_hash_table_iter_init (&inner, (GHashTable *)outer_value);
1582       while (g_hash_table_iter_next (&inner, &inner_key, &inner_value))
1583         {
1584           g_hash_table_insert (to_digest_table,
1585                                g_strdup (inner_key),
1586                                modulemd_rpm_map_entry_copy (inner_value));
1587         }
1588     }
1589 }
1590 
1591 static ModulemdModuleStream *
modulemd_module_stream_v2_copy(ModulemdModuleStream * self,const gchar * module_name,const gchar * module_stream)1592 modulemd_module_stream_v2_copy (ModulemdModuleStream *self,
1593                                 const gchar *module_name,
1594                                 const gchar *module_stream)
1595 {
1596   ModulemdModuleStreamV2 *v2_self = NULL;
1597   g_autoptr (ModulemdModuleStreamV2) copy = NULL;
1598   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self), NULL);
1599   v2_self = MODULEMD_MODULE_STREAM_V2 (self);
1600 
1601   copy = MODULEMD_MODULE_STREAM_V2 (
1602     MODULEMD_MODULE_STREAM_CLASS (modulemd_module_stream_v2_parent_class)
1603       ->copy (self, module_name, module_stream));
1604 
1605   /* Properties */
1606   STREAM_COPY_IF_SET (v2, copy, v2_self, arch);
1607   STREAM_COPY_IF_SET (v2, copy, v2_self, buildopts);
1608   STREAM_COPY_IF_SET (v2, copy, v2_self, community);
1609   STREAM_COPY_IF_SET_WITH_LOCALE (v2, copy, v2_self, description);
1610   STREAM_COPY_IF_SET (v2, copy, v2_self, documentation);
1611   STREAM_COPY_IF_SET_WITH_LOCALE (v2, copy, v2_self, summary);
1612   STREAM_COPY_IF_SET (v2, copy, v2_self, tracker);
1613   copy->static_context = v2_self->static_context;
1614 
1615   /* Internal Data Structures: With replace function */
1616   STREAM_REPLACE_HASHTABLE (v2, copy, v2_self, content_licenses);
1617   STREAM_REPLACE_HASHTABLE (v2, copy, v2_self, module_licenses);
1618   STREAM_REPLACE_HASHTABLE (v2, copy, v2_self, rpm_api);
1619   STREAM_REPLACE_HASHTABLE (v2, copy, v2_self, rpm_artifacts);
1620   STREAM_REPLACE_HASHTABLE (v2, copy, v2_self, rpm_filters);
1621   STREAM_REPLACE_HASHTABLE (v2, copy, v2_self, demodularized_rpms);
1622 
1623   /* Internal Data Structures: With add on value */
1624   COPY_HASHTABLE_BY_VALUE_ADDER (
1625     copy, v2_self, rpm_components, modulemd_module_stream_v2_add_component);
1626   COPY_HASHTABLE_BY_VALUE_ADDER (
1627     copy, v2_self, module_components, modulemd_module_stream_v2_add_component);
1628   COPY_HASHTABLE_BY_VALUE_ADDER (
1629     copy, v2_self, profiles, modulemd_module_stream_v2_add_profile);
1630   COPY_HASHTABLE_BY_VALUE_ADDER (
1631     copy, v2_self, servicelevels, modulemd_module_stream_v2_add_servicelevel);
1632 
1633   STREAM_REPLACE_HASHTABLE (v2, copy, v2_self, dependencies);
1634 
1635   copy_rpm_artifact_map (v2_self, copy);
1636 
1637   STREAM_COPY_IF_SET (v2, copy, v2_self, xmd);
1638 
1639   modulemd_module_stream_v2_associate_obsoletes (
1640     copy, modulemd_module_stream_v2_get_obsoletes (v2_self));
1641 
1642   return MODULEMD_MODULE_STREAM (g_steal_pointer (&copy));
1643 }
1644 
1645 
1646 static gboolean
depends_on_stream(ModulemdModuleStreamV2 * self,const gchar * module_name,const gchar * stream_name,gboolean is_builddep)1647 depends_on_stream (ModulemdModuleStreamV2 *self,
1648                    const gchar *module_name,
1649                    const gchar *stream_name,
1650                    gboolean is_builddep)
1651 {
1652   ModulemdDependencies *dep = NULL;
1653 
1654   /* Iterate through all of the dependency objects */
1655   for (gint i = 0; i < self->dependencies->len; i++)
1656     {
1657       dep = g_ptr_array_index (self->dependencies, i);
1658       if (is_builddep)
1659         {
1660           if (modulemd_dependencies_buildrequires_module_and_stream (
1661                 dep, module_name, stream_name))
1662             {
1663               return TRUE;
1664             }
1665         }
1666       else
1667         {
1668           if (modulemd_dependencies_requires_module_and_stream (
1669                 dep, module_name, stream_name))
1670             {
1671               return TRUE;
1672             }
1673         }
1674     }
1675 
1676   return FALSE;
1677 }
1678 
1679 static gboolean
modulemd_module_stream_v2_depends_on_stream(ModulemdModuleStream * self,const gchar * module_name,const gchar * stream_name)1680 modulemd_module_stream_v2_depends_on_stream (ModulemdModuleStream *self,
1681                                              const gchar *module_name,
1682                                              const gchar *stream_name)
1683 {
1684   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self), FALSE);
1685   g_return_val_if_fail (module_name && stream_name, FALSE);
1686 
1687   return depends_on_stream (
1688     MODULEMD_MODULE_STREAM_V2 (self), module_name, stream_name, FALSE);
1689 }
1690 
1691 
1692 static gboolean
modulemd_module_stream_v2_build_depends_on_stream(ModulemdModuleStream * self,const gchar * module_name,const gchar * stream_name)1693 modulemd_module_stream_v2_build_depends_on_stream (ModulemdModuleStream *self,
1694                                                    const gchar *module_name,
1695                                                    const gchar *stream_name)
1696 {
1697   g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM_V2 (self), FALSE);
1698   g_return_val_if_fail (module_name && stream_name, FALSE);
1699 
1700   return depends_on_stream (
1701     MODULEMD_MODULE_STREAM_V2 (self), module_name, stream_name, TRUE);
1702 }
1703 
1704 
1705 static void
modulemd_module_stream_v2_class_init(ModulemdModuleStreamV2Class * klass)1706 modulemd_module_stream_v2_class_init (ModulemdModuleStreamV2Class *klass)
1707 {
1708   GObjectClass *object_class = G_OBJECT_CLASS (klass);
1709   ModulemdModuleStreamClass *stream_class =
1710     MODULEMD_MODULE_STREAM_CLASS (object_class);
1711 
1712   object_class->finalize = modulemd_module_stream_v2_finalize;
1713   object_class->get_property = modulemd_module_stream_v2_get_property;
1714   object_class->set_property = modulemd_module_stream_v2_set_property;
1715 
1716   stream_class->get_mdversion = modulemd_module_stream_v2_get_mdversion;
1717   stream_class->copy = modulemd_module_stream_v2_copy;
1718   stream_class->equals = modulemd_module_stream_v2_equals;
1719   stream_class->validate = modulemd_module_stream_v2_validate;
1720   stream_class->depends_on_stream =
1721     modulemd_module_stream_v2_depends_on_stream;
1722   stream_class->build_depends_on_stream =
1723     modulemd_module_stream_v2_build_depends_on_stream;
1724 
1725 
1726   properties[PROP_ARCH] = g_param_spec_string (
1727     "arch",
1728     "Module Artifact Architecture",
1729     "The architecture of the produced artifacts",
1730     NULL,
1731     G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
1732 
1733   properties[PROP_BUILDOPTS] =
1734     g_param_spec_object ("buildopts",
1735                          "Module Build Options",
1736                          "Build options for module components",
1737                          MODULEMD_TYPE_BUILDOPTS,
1738                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1739 
1740   properties[PROP_COMMUNITY] = g_param_spec_string (
1741     "community",
1742     "Module Community Website",
1743     "The website address of the upstream community for this module",
1744     NULL,
1745     G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
1746 
1747   properties[PROP_DOCUMENTATION] = g_param_spec_string (
1748     "documentation",
1749     "Module Documentation Website",
1750     "The website address of the upstream documentation for this module",
1751     NULL,
1752     G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
1753 
1754   properties[PROP_TRACKER] = g_param_spec_string (
1755     "tracker",
1756     "Module Bug Tracker Website",
1757     "The website address of the upstream bug tracker for this module",
1758     NULL,
1759     G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
1760 
1761   properties[PROP_STATIC_CONTEXT] =
1762     g_param_spec_boolean ("static-context",
1763                           "Static Context",
1764                           "Whether the context is static",
1765                           0,
1766                           G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
1767 
1768   g_object_class_install_properties (object_class, N_PROPS, properties);
1769 }
1770 
1771 static void
modulemd_module_stream_v2_init(ModulemdModuleStreamV2 * self)1772 modulemd_module_stream_v2_init (ModulemdModuleStreamV2 *self)
1773 {
1774   /* Properties */
1775 
1776   /* Internal Data Structures */
1777   self->module_components =
1778     g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
1779   self->rpm_components =
1780     g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
1781 
1782 
1783   self->content_licenses =
1784     g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1785   self->module_licenses =
1786     g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1787 
1788   self->profiles =
1789     g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
1790 
1791   self->rpm_api =
1792     g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1793 
1794   self->rpm_artifacts =
1795     g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1796 
1797   self->rpm_artifact_map = g_hash_table_new_full (
1798     g_str_hash, g_str_equal, g_free, modulemd_hash_table_unref);
1799 
1800   self->rpm_filters =
1801     g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1802 
1803   self->demodularized_rpms =
1804     g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1805 
1806   self->servicelevels =
1807     g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
1808 
1809   /* The common case is for a single entry, so we'll optimize for that when
1810    * preallocating
1811    */
1812   self->dependencies = g_ptr_array_new_full (1, g_object_unref);
1813 }
1814 
1815 
1816 static gboolean
1817 modulemd_module_stream_v2_parse_licenses (yaml_parser_t *parser,
1818                                           ModulemdModuleStreamV2 *modulestream,
1819                                           gboolean strict,
1820                                           gboolean only_packager,
1821                                           GError **error);
1822 
1823 static gboolean
1824 modulemd_module_stream_v2_parse_servicelevels (
1825   yaml_parser_t *parser,
1826   ModulemdModuleStreamV2 *modulestream,
1827   gboolean strict,
1828   GError **error);
1829 
1830 static gboolean
1831 modulemd_module_stream_v2_parse_deps (yaml_parser_t *parser,
1832                                       ModulemdModuleStreamV2 *modulestream,
1833                                       gboolean strict,
1834                                       GError **error);
1835 
1836 static gboolean
1837 modulemd_module_stream_v2_parse_refs (yaml_parser_t *parser,
1838                                       ModulemdModuleStreamV2 *modulestream,
1839                                       gboolean strict,
1840                                       GError **error);
1841 
1842 static gboolean
1843 modulemd_module_stream_v2_parse_profiles (yaml_parser_t *parser,
1844                                           ModulemdModuleStreamV2 *modulestream,
1845                                           gboolean strict,
1846                                           GError **error);
1847 
1848 static gboolean
1849 modulemd_module_stream_v2_parse_components (
1850   yaml_parser_t *parser,
1851   ModulemdModuleStreamV2 *modulestream,
1852   gboolean strict,
1853   GError **error);
1854 
1855 static gboolean
1856 modulemd_module_stream_v2_parse_artifacts (
1857   yaml_parser_t *parser,
1858   ModulemdModuleStreamV2 *modulestream,
1859   gboolean strict,
1860   GError **error);
1861 
1862 
1863 ModulemdModuleStreamV2 *
modulemd_module_stream_v2_parse_yaml(ModulemdSubdocumentInfo * subdoc,gboolean strict,gboolean only_packager,GError ** error)1864 modulemd_module_stream_v2_parse_yaml (ModulemdSubdocumentInfo *subdoc,
1865                                       gboolean strict,
1866                                       gboolean only_packager,
1867                                       GError **error)
1868 {
1869   MODULEMD_INIT_TRACE ();
1870   MMD_INIT_YAML_PARSER (parser);
1871   MMD_INIT_YAML_EVENT (event);
1872   gboolean done = FALSE;
1873   g_autoptr (GError) nested_error = NULL;
1874   g_autoptr (ModulemdModuleStreamV2) modulestream = NULL;
1875   g_autoptr (GHashTable) set = NULL;
1876   g_autoptr (ModulemdBuildopts) buildopts = NULL;
1877   g_autoptr (GVariant) xmd = NULL;
1878   guint64 version;
1879   gboolean static_context;
1880 
1881   if (!modulemd_subdocument_info_get_data_parser (
1882         subdoc, &parser, strict, error))
1883     {
1884       return FALSE;
1885     }
1886 
1887   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1888 
1889   modulestream = modulemd_module_stream_v2_new (NULL, NULL);
1890 
1891   /* Read the MAPPING_START */
1892   YAML_PARSER_PARSE_WITH_EXIT (&parser, &event, error);
1893   if (event.type != YAML_MAPPING_START_EVENT)
1894     {
1895       MMD_YAML_ERROR_EVENT_EXIT (
1896         error, event, "Data section did not begin with a map.");
1897     }
1898 
1899   /* Process through the mapping */
1900   while (!done)
1901     {
1902       YAML_PARSER_PARSE_WITH_EXIT (&parser, &event, error);
1903 
1904       switch (event.type)
1905         {
1906         case YAML_MAPPING_END_EVENT: done = TRUE; break;
1907 
1908         case YAML_SCALAR_EVENT:
1909           /* Mapping Keys */
1910 
1911           /* Module Name */
1912           if (g_str_equal ((const gchar *)event.data.scalar.value, "name") &&
1913               !only_packager)
1914             {
1915               MMD_SET_PARSED_YAML_STRING (
1916                 &parser,
1917                 error,
1918                 modulemd_module_stream_set_module_name,
1919                 MODULEMD_MODULE_STREAM (modulestream));
1920             }
1921 
1922           /* Module Stream Name */
1923           else if (g_str_equal ((const gchar *)event.data.scalar.value,
1924                                 "stream") &&
1925                    !only_packager)
1926             {
1927               MMD_SET_PARSED_YAML_STRING (
1928                 &parser,
1929                 error,
1930                 modulemd_module_stream_set_stream_name,
1931                 MODULEMD_MODULE_STREAM (modulestream));
1932             }
1933 
1934           /* Module Version */
1935           else if (g_str_equal ((const gchar *)event.data.scalar.value,
1936                                 "version") &&
1937                    !only_packager)
1938             {
1939               version = modulemd_yaml_parse_uint64 (&parser, &nested_error);
1940               if (nested_error)
1941                 {
1942                   g_propagate_error (error, g_steal_pointer (&nested_error));
1943                   return NULL;
1944                 }
1945 
1946               modulemd_module_stream_set_version (
1947                 MODULEMD_MODULE_STREAM (modulestream), version);
1948             }
1949 
1950           /* Module Context */
1951           else if (g_str_equal ((const gchar *)event.data.scalar.value,
1952                                 "context") &&
1953                    !only_packager)
1954             {
1955               MMD_SET_PARSED_YAML_STRING (
1956                 &parser,
1957                 error,
1958                 modulemd_module_stream_set_context,
1959                 MODULEMD_MODULE_STREAM (modulestream));
1960             }
1961 
1962           else if (g_str_equal ((const gchar *)event.data.scalar.value,
1963                                 "static_context"))
1964             {
1965               static_context =
1966                 modulemd_yaml_parse_bool (&parser, &nested_error);
1967               if (nested_error)
1968                 {
1969                   g_propagate_error (error, g_steal_pointer (&nested_error));
1970                   return NULL;
1971                 }
1972 
1973               if (static_context)
1974                 {
1975                   modulemd_module_stream_v2_set_static_context (modulestream);
1976                 }
1977               else
1978                 {
1979                   modulemd_module_stream_v2_unset_static_context (
1980                     modulestream);
1981                 }
1982             }
1983 
1984           /* Module Artifact Architecture */
1985           else if (g_str_equal ((const gchar *)event.data.scalar.value,
1986                                 "arch") &&
1987                    !only_packager)
1988             {
1989               MMD_SET_PARSED_YAML_STRING (&parser,
1990                                           error,
1991                                           modulemd_module_stream_v2_set_arch,
1992                                           modulestream);
1993             }
1994 
1995           /* Module Summary */
1996           else if (g_str_equal ((const gchar *)event.data.scalar.value,
1997                                 "summary"))
1998             {
1999               MMD_SET_PARSED_YAML_STRING (
2000                 &parser,
2001                 error,
2002                 modulemd_module_stream_v2_set_summary,
2003                 modulestream);
2004             }
2005 
2006           /* Module Description */
2007           else if (g_str_equal ((const gchar *)event.data.scalar.value,
2008                                 "description"))
2009             {
2010               MMD_SET_PARSED_YAML_STRING (
2011                 &parser,
2012                 error,
2013                 modulemd_module_stream_v2_set_description,
2014                 modulestream);
2015             }
2016 
2017           /* Service Levels */
2018           else if (g_str_equal ((const gchar *)event.data.scalar.value,
2019                                 "servicelevels") &&
2020                    !only_packager)
2021             {
2022               if (!modulemd_module_stream_v2_parse_servicelevels (
2023                     &parser, modulestream, strict, &nested_error))
2024                 {
2025                   g_propagate_error (error, g_steal_pointer (&nested_error));
2026                   return NULL;
2027                 }
2028             }
2029 
2030           /* Licences */
2031           else if (g_str_equal ((const gchar *)event.data.scalar.value,
2032                                 "license"))
2033             {
2034               if (!modulemd_module_stream_v2_parse_licenses (&parser,
2035                                                              modulestream,
2036                                                              strict,
2037                                                              only_packager,
2038                                                              &nested_error))
2039                 {
2040                   g_propagate_error (error, g_steal_pointer (&nested_error));
2041                   return NULL;
2042                 }
2043             }
2044 
2045           /* Extensible Metadata */
2046           else if (g_str_equal ((const gchar *)event.data.scalar.value,
2047                                 "xmd") &&
2048                    !only_packager)
2049             {
2050               xmd = mmd_parse_xmd (&parser, &nested_error);
2051               if (!xmd)
2052                 {
2053                   g_propagate_error (error, g_steal_pointer (&nested_error));
2054                   return NULL;
2055                 }
2056               modulemd_module_stream_v2_set_xmd (modulestream, xmd);
2057               g_clear_pointer (&xmd, g_variant_unref);
2058             }
2059 
2060           /* Dependencies */
2061           else if (g_str_equal ((const gchar *)event.data.scalar.value,
2062                                 "dependencies"))
2063             {
2064               if (!modulemd_module_stream_v2_parse_deps (
2065                     &parser, modulestream, strict, &nested_error))
2066                 {
2067                   g_propagate_error (error, g_steal_pointer (&nested_error));
2068                   return NULL;
2069                 }
2070             }
2071 
2072           /* References */
2073           else if (g_str_equal ((const gchar *)event.data.scalar.value,
2074                                 "references"))
2075             {
2076               if (!modulemd_module_stream_v2_parse_refs (
2077                     &parser, modulestream, strict, &nested_error))
2078                 {
2079                   g_propagate_error (error, g_steal_pointer (&nested_error));
2080                   return NULL;
2081                 }
2082             }
2083 
2084           /* Profiles */
2085           else if (g_str_equal ((const gchar *)event.data.scalar.value,
2086                                 "profiles"))
2087             {
2088               if (!modulemd_module_stream_v2_parse_profiles (
2089                     &parser, modulestream, strict, &nested_error))
2090                 {
2091                   g_propagate_error (error, g_steal_pointer (&nested_error));
2092                   return NULL;
2093                 }
2094             }
2095 
2096           /* API */
2097           else if (g_str_equal ((const gchar *)event.data.scalar.value, "api"))
2098             {
2099               set = modulemd_yaml_parse_string_set_from_map (
2100                 &parser, "rpms", strict, &nested_error);
2101               modulemd_module_stream_v2_replace_rpm_api (modulestream, set);
2102               g_clear_pointer (&set, g_hash_table_unref);
2103             }
2104 
2105           /* Filter */
2106           else if (g_str_equal ((const gchar *)event.data.scalar.value,
2107                                 "filter"))
2108             {
2109               set = modulemd_yaml_parse_string_set_from_map (
2110                 &parser, "rpms", strict, &nested_error);
2111               modulemd_module_stream_v2_replace_rpm_filters (modulestream,
2112                                                              set);
2113               g_clear_pointer (&set, g_hash_table_unref);
2114             }
2115 
2116           /* Demodularized Packages */
2117           else if (g_str_equal ((const gchar *)event.data.scalar.value,
2118                                 "demodularized"))
2119             {
2120               set = modulemd_yaml_parse_string_set_from_map (
2121                 &parser, "rpms", strict, &nested_error);
2122               modulemd_module_stream_v2_replace_demodularized_rpms (
2123                 modulestream, set);
2124               g_clear_pointer (&set, g_hash_table_unref);
2125             }
2126 
2127           /* Build Options */
2128           else if (g_str_equal ((const gchar *)event.data.scalar.value,
2129                                 "buildopts") &&
2130                    !only_packager)
2131             {
2132               buildopts =
2133                 modulemd_buildopts_parse_yaml (&parser, strict, &nested_error);
2134               if (!buildopts)
2135                 {
2136                   g_propagate_error (error, g_steal_pointer (&nested_error));
2137                   return NULL;
2138                 }
2139 
2140               modulemd_module_stream_v2_set_buildopts (modulestream,
2141                                                        buildopts);
2142               g_clear_object (&buildopts);
2143             }
2144 
2145           /* Components */
2146           else if (g_str_equal ((const gchar *)event.data.scalar.value,
2147                                 "components"))
2148             {
2149               if (!modulemd_module_stream_v2_parse_components (
2150                     &parser, modulestream, strict, &nested_error))
2151                 {
2152                   g_propagate_error (error, g_steal_pointer (&nested_error));
2153                   return NULL;
2154                 }
2155             }
2156 
2157           /* Artifacts */
2158           else if (g_str_equal ((const gchar *)event.data.scalar.value,
2159                                 "artifacts") &&
2160                    !only_packager)
2161             {
2162               if (!modulemd_module_stream_v2_parse_artifacts (
2163                     &parser, modulestream, strict, &nested_error))
2164                 {
2165                   g_propagate_error (error, g_steal_pointer (&nested_error));
2166                   return NULL;
2167                 }
2168 
2169               g_clear_pointer (&set, g_hash_table_unref);
2170             }
2171 
2172           else
2173             {
2174               SKIP_UNKNOWN (&parser,
2175                             NULL,
2176                             "Unexpected key in data: %s",
2177                             (const gchar *)event.data.scalar.value);
2178               break;
2179             }
2180           break;
2181 
2182         default:
2183           MMD_YAML_ERROR_EVENT_EXIT (
2184             error,
2185             event,
2186             "Unexpected YAML event in ModuleStreamV2: %s",
2187             mmd_yaml_get_event_name (event.type));
2188           break;
2189         }
2190       yaml_event_delete (&event);
2191     }
2192 
2193   return g_steal_pointer (&modulestream);
2194 }
2195 
2196 
2197 static gboolean
modulemd_module_stream_v2_parse_licenses(yaml_parser_t * parser,ModulemdModuleStreamV2 * modulestream,gboolean strict,gboolean only_packager,GError ** error)2198 modulemd_module_stream_v2_parse_licenses (yaml_parser_t *parser,
2199                                           ModulemdModuleStreamV2 *modulestream,
2200                                           gboolean strict,
2201                                           gboolean only_packager,
2202                                           GError **error)
2203 {
2204   MODULEMD_INIT_TRACE ();
2205   MMD_INIT_YAML_EVENT (event);
2206   gboolean done = FALSE;
2207   gboolean in_map = FALSE;
2208   g_autoptr (GError) nested_error = NULL;
2209   g_autoptr (GHashTable) set = NULL;
2210 
2211   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2212 
2213   /* Process through the mapping */
2214   while (!done)
2215     {
2216       YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
2217 
2218       switch (event.type)
2219         {
2220         case YAML_MAPPING_START_EVENT:
2221           if (in_map)
2222             {
2223               MMD_YAML_ERROR_EVENT_EXIT_BOOL (
2224                 error,
2225                 event,
2226                 "Unexpected extra MAPPING_START event in licenses");
2227             }
2228           in_map = TRUE;
2229           break;
2230 
2231         case YAML_MAPPING_END_EVENT:
2232           if (!in_map)
2233             {
2234               MMD_YAML_ERROR_EVENT_EXIT_BOOL (
2235                 error, event, "Unexpected MAPPING_END event in licenses");
2236             }
2237           done = TRUE;
2238           break;
2239 
2240         case YAML_SCALAR_EVENT:
2241           if (!in_map)
2242             {
2243               MMD_YAML_ERROR_EVENT_EXIT_BOOL (
2244                 error, event, "Received scalar outside of mapping");
2245             }
2246 
2247           if (g_str_equal ((const gchar *)event.data.scalar.value, "module"))
2248             {
2249               set = modulemd_yaml_parse_string_set (parser, &nested_error);
2250               if (!set)
2251                 {
2252                   g_propagate_error (error, g_steal_pointer (&nested_error));
2253                   return FALSE;
2254                 }
2255               modulemd_module_stream_v2_replace_module_licenses (modulestream,
2256                                                                  set);
2257               g_clear_pointer (&set, g_hash_table_unref);
2258             }
2259           else if (g_str_equal ((const gchar *)event.data.scalar.value,
2260                                 "content") &&
2261                    !only_packager)
2262             {
2263               set = modulemd_yaml_parse_string_set (parser, &nested_error);
2264               modulemd_module_stream_v2_replace_content_licenses (modulestream,
2265                                                                   set);
2266               g_clear_pointer (&set, g_hash_table_unref);
2267             }
2268           else
2269             {
2270               SKIP_UNKNOWN (parser,
2271                             FALSE,
2272                             "Unexpected key in licenses: %s",
2273                             (const gchar *)event.data.scalar.value);
2274               break;
2275             }
2276 
2277           break;
2278 
2279         default:
2280           MMD_YAML_ERROR_EVENT_EXIT_BOOL (
2281             error,
2282             event,
2283             "Unexpected YAML event in licenses: %s",
2284             mmd_yaml_get_event_name (event.type));
2285           break;
2286         }
2287       yaml_event_delete (&event);
2288     }
2289 
2290   return TRUE;
2291 }
2292 
2293 
2294 static gboolean
modulemd_module_stream_v2_parse_servicelevels(yaml_parser_t * parser,ModulemdModuleStreamV2 * modulestream,gboolean strict,GError ** error)2295 modulemd_module_stream_v2_parse_servicelevels (
2296   yaml_parser_t *parser,
2297   ModulemdModuleStreamV2 *modulestream,
2298   gboolean strict,
2299   GError **error)
2300 {
2301   MODULEMD_INIT_TRACE ();
2302   MMD_INIT_YAML_EVENT (event);
2303   gboolean done = FALSE;
2304   gboolean in_map = FALSE;
2305   const gchar *name = NULL;
2306   g_autoptr (ModulemdServiceLevel) sl = NULL;
2307   g_autoptr (GError) nested_error = NULL;
2308 
2309   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2310 
2311   /* Process through the mapping */
2312   while (!done)
2313     {
2314       YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
2315 
2316       switch (event.type)
2317         {
2318         case YAML_MAPPING_START_EVENT:
2319           if (in_map)
2320             {
2321               MMD_YAML_ERROR_EVENT_EXIT_BOOL (
2322                 error,
2323                 event,
2324                 "Unexpected extra MAPPING_START event in servicelevels");
2325             }
2326           in_map = TRUE;
2327           break;
2328 
2329         case YAML_MAPPING_END_EVENT:
2330           if (!in_map)
2331             {
2332               MMD_YAML_ERROR_EVENT_EXIT_BOOL (
2333                 error, event, "Unexpected MAPPING_END event in servicelevels");
2334             }
2335           done = TRUE;
2336           break;
2337 
2338         case YAML_SCALAR_EVENT:
2339           if (!in_map)
2340             {
2341               MMD_YAML_ERROR_EVENT_EXIT_BOOL (
2342                 error, event, "Received scalar outside of mapping");
2343             }
2344 
2345           name = (const gchar *)event.data.scalar.value;
2346 
2347           sl = modulemd_service_level_parse_yaml (
2348             parser, name, strict, &nested_error);
2349           if (!sl)
2350             {
2351               g_propagate_error (error, g_steal_pointer (&nested_error));
2352               return FALSE;
2353             }
2354 
2355           modulemd_module_stream_v2_add_servicelevel (modulestream, sl);
2356           g_clear_object (&sl);
2357 
2358           break;
2359 
2360         default:
2361           MMD_YAML_ERROR_EVENT_EXIT_BOOL (
2362             error,
2363             event,
2364             "Unexpected YAML event in servicelevels: %s",
2365             mmd_yaml_get_event_name (event.type));
2366           break;
2367         }
2368       yaml_event_delete (&event);
2369     }
2370 
2371   return TRUE;
2372 }
2373 
2374 static gboolean
modulemd_module_stream_v2_parse_deps(yaml_parser_t * parser,ModulemdModuleStreamV2 * modulestream,gboolean strict,GError ** error)2375 modulemd_module_stream_v2_parse_deps (yaml_parser_t *parser,
2376                                       ModulemdModuleStreamV2 *modulestream,
2377                                       gboolean strict,
2378                                       GError **error)
2379 {
2380   MODULEMD_INIT_TRACE ();
2381   MMD_INIT_YAML_EVENT (event);
2382   gboolean done = FALSE;
2383   g_autoptr (ModulemdDependencies) deps = NULL;
2384   g_autoptr (GError) nested_error = NULL;
2385 
2386   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2387 
2388   /* Process through the sequence */
2389   /* We *must* get a SEQUENCE_START here */
2390   YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
2391   if (event.type != YAML_SEQUENCE_START_EVENT)
2392     {
2393       MMD_YAML_ERROR_EVENT_EXIT_BOOL (
2394         error,
2395         event,
2396         "Got %s instead of SEQUENCE_START in dependencies.",
2397         mmd_yaml_get_event_name (event.type));
2398     }
2399 
2400   while (!done)
2401     {
2402       YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
2403 
2404       switch (event.type)
2405         {
2406         case YAML_SEQUENCE_END_EVENT: done = TRUE; break;
2407 
2408         case YAML_MAPPING_START_EVENT:
2409           deps =
2410             modulemd_dependencies_parse_yaml (parser, strict, &nested_error);
2411           if (!deps)
2412             {
2413               g_propagate_error (error, g_steal_pointer (&nested_error));
2414               return FALSE;
2415             }
2416 
2417           modulemd_module_stream_v2_add_dependencies (modulestream, deps);
2418           g_clear_object (&deps);
2419           break;
2420 
2421         default:
2422           MMD_YAML_ERROR_EVENT_EXIT_BOOL (
2423             error,
2424             event,
2425             "Unexpected YAML event in dependencies: %s",
2426             mmd_yaml_get_event_name (event.type));
2427           break;
2428         }
2429       yaml_event_delete (&event);
2430     }
2431 
2432   return TRUE;
2433 }
2434 
2435 
2436 static gboolean
modulemd_module_stream_v2_parse_refs(yaml_parser_t * parser,ModulemdModuleStreamV2 * modulestream,gboolean strict,GError ** error)2437 modulemd_module_stream_v2_parse_refs (yaml_parser_t *parser,
2438                                       ModulemdModuleStreamV2 *modulestream,
2439                                       gboolean strict,
2440                                       GError **error)
2441 {
2442   MODULEMD_INIT_TRACE ();
2443   MMD_INIT_YAML_EVENT (event);
2444   gboolean done = FALSE;
2445   g_autofree gchar *scalar = NULL;
2446   g_autoptr (GError) nested_error = NULL;
2447 
2448   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2449 
2450   /* Process through the map */
2451   /* We *must* get a MAPPING_START here */
2452   YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
2453   if (event.type != YAML_MAPPING_START_EVENT)
2454     {
2455       MMD_YAML_ERROR_EVENT_EXIT_BOOL (
2456         error,
2457         event,
2458         "Got %s instead of MAPPING_START in dependencies.",
2459         mmd_yaml_get_event_name (event.type));
2460     }
2461 
2462   while (!done)
2463     {
2464       YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
2465 
2466       switch (event.type)
2467         {
2468         case YAML_MAPPING_END_EVENT: done = TRUE; break;
2469 
2470         case YAML_SCALAR_EVENT:
2471           if (g_str_equal ((const gchar *)event.data.scalar.value,
2472                            "community"))
2473             {
2474               scalar = modulemd_yaml_parse_string (parser, &nested_error);
2475               if (!scalar)
2476                 {
2477                   g_propagate_error (error, g_steal_pointer (&nested_error));
2478                   return FALSE;
2479                 }
2480 
2481               modulemd_module_stream_v2_set_community (modulestream, scalar);
2482               g_clear_pointer (&scalar, g_free);
2483             }
2484 
2485           else if (g_str_equal ((const gchar *)event.data.scalar.value,
2486                                 "documentation"))
2487             {
2488               scalar = modulemd_yaml_parse_string (parser, &nested_error);
2489               if (!scalar)
2490                 {
2491                   g_propagate_error (error, g_steal_pointer (&nested_error));
2492                   return FALSE;
2493                 }
2494 
2495               modulemd_module_stream_v2_set_documentation (modulestream,
2496                                                            scalar);
2497               g_clear_pointer (&scalar, g_free);
2498             }
2499 
2500           else if (g_str_equal ((const gchar *)event.data.scalar.value,
2501                                 "tracker"))
2502             {
2503               scalar = modulemd_yaml_parse_string (parser, &nested_error);
2504               if (!scalar)
2505                 {
2506                   g_propagate_error (error, g_steal_pointer (&nested_error));
2507                   return FALSE;
2508                 }
2509 
2510               modulemd_module_stream_v2_set_tracker (modulestream, scalar);
2511               g_clear_pointer (&scalar, g_free);
2512             }
2513 
2514           else
2515             {
2516               SKIP_UNKNOWN (parser,
2517                             FALSE,
2518                             "Unexpected key in references: %s",
2519                             (const gchar *)event.data.scalar.value);
2520               break;
2521             }
2522           break;
2523 
2524         default:
2525           MMD_YAML_ERROR_EVENT_EXIT_BOOL (
2526             error,
2527             event,
2528             "Unexpected YAML event in dependencies: %s",
2529             mmd_yaml_get_event_name (event.type));
2530           break;
2531         }
2532       yaml_event_delete (&event);
2533     }
2534 
2535   return TRUE;
2536 }
2537 
2538 
2539 static gboolean
modulemd_module_stream_v2_parse_profiles(yaml_parser_t * parser,ModulemdModuleStreamV2 * modulestream,gboolean strict,GError ** error)2540 modulemd_module_stream_v2_parse_profiles (yaml_parser_t *parser,
2541                                           ModulemdModuleStreamV2 *modulestream,
2542                                           gboolean strict,
2543                                           GError **error)
2544 {
2545   MODULEMD_INIT_TRACE ();
2546   MMD_INIT_YAML_EVENT (event);
2547   gboolean done = FALSE;
2548   g_autoptr (GError) nested_error = NULL;
2549   g_autoptr (ModulemdProfile) profile = NULL;
2550 
2551   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2552 
2553   /* Process through the map */
2554   /* We *must* get a MAPPING_START here */
2555   YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
2556   if (event.type != YAML_MAPPING_START_EVENT)
2557     {
2558       MMD_YAML_ERROR_EVENT_EXIT_BOOL (
2559         error,
2560         event,
2561         "Got %s instead of MAPPING_START in profiles.",
2562         mmd_yaml_get_event_name (event.type));
2563     }
2564 
2565   while (!done)
2566     {
2567       YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
2568 
2569       switch (event.type)
2570         {
2571         case YAML_MAPPING_END_EVENT: done = TRUE; break;
2572 
2573         case YAML_SCALAR_EVENT:
2574           profile = modulemd_profile_parse_yaml (
2575             parser,
2576             (const gchar *)event.data.scalar.value,
2577             strict,
2578             &nested_error);
2579           if (!profile)
2580             {
2581               g_propagate_error (error, g_steal_pointer (&nested_error));
2582               return FALSE;
2583             }
2584 
2585           modulemd_module_stream_v2_add_profile (modulestream, profile);
2586           g_clear_pointer (&profile, g_object_unref);
2587           break;
2588 
2589         default:
2590           MMD_YAML_ERROR_EVENT_EXIT_BOOL (
2591             error,
2592             event,
2593             "Unexpected YAML event in dependencies: %s",
2594             mmd_yaml_get_event_name (event.type));
2595           break;
2596         }
2597       yaml_event_delete (&event);
2598     }
2599 
2600   return TRUE;
2601 }
2602 
2603 
2604 static gboolean
2605 modulemd_module_stream_v2_parse_rpm_components (
2606   yaml_parser_t *parser,
2607   ModulemdModuleStreamV2 *modulestream,
2608   gboolean strict,
2609   GError **error);
2610 static gboolean
2611 modulemd_module_stream_v2_parse_module_components (
2612   yaml_parser_t *parser,
2613   ModulemdModuleStreamV2 *modulestream,
2614   gboolean strict,
2615   GError **error);
2616 
2617 
2618 static gboolean
modulemd_module_stream_v2_parse_components(yaml_parser_t * parser,ModulemdModuleStreamV2 * modulestream,gboolean strict,GError ** error)2619 modulemd_module_stream_v2_parse_components (
2620   yaml_parser_t *parser,
2621   ModulemdModuleStreamV2 *modulestream,
2622   gboolean strict,
2623   GError **error)
2624 {
2625   MODULEMD_INIT_TRACE ();
2626   MMD_INIT_YAML_EVENT (event);
2627   gboolean done = FALSE;
2628   g_autoptr (GError) nested_error = NULL;
2629 
2630   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2631 
2632   /* Process through the sequence */
2633   /* We *must* get a MAPPING_START here */
2634   YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
2635   if (event.type != YAML_MAPPING_START_EVENT)
2636     {
2637       MMD_YAML_ERROR_EVENT_EXIT_BOOL (
2638         error,
2639         event,
2640         "Got %s instead of MAPPING_START in components.",
2641         mmd_yaml_get_event_name (event.type));
2642     }
2643 
2644   while (!done)
2645     {
2646       YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
2647 
2648       switch (event.type)
2649         {
2650         case YAML_MAPPING_END_EVENT: done = TRUE; break;
2651 
2652         case YAML_SCALAR_EVENT:
2653           if (g_str_equal ((const gchar *)event.data.scalar.value, "rpms"))
2654             {
2655               if (!modulemd_module_stream_v2_parse_rpm_components (
2656                     parser, modulestream, strict, &nested_error))
2657                 {
2658                   g_propagate_error (error, g_steal_pointer (&nested_error));
2659                   return FALSE;
2660                 }
2661             }
2662 
2663           else if (g_str_equal ((const gchar *)event.data.scalar.value,
2664                                 "modules"))
2665             {
2666               if (!modulemd_module_stream_v2_parse_module_components (
2667                     parser, modulestream, strict, &nested_error))
2668                 {
2669                   g_propagate_error (error, g_steal_pointer (&nested_error));
2670                   return FALSE;
2671                 }
2672             }
2673 
2674           else
2675             {
2676               SKIP_UNKNOWN (parser,
2677                             FALSE,
2678                             "Unexpected key in components: %s",
2679                             (const gchar *)event.data.scalar.value);
2680             }
2681 
2682           break;
2683 
2684 
2685         default:
2686           MMD_YAML_ERROR_EVENT_EXIT_BOOL (
2687             error,
2688             event,
2689             "Unexpected YAML event in components: %s",
2690             mmd_yaml_get_event_name (event.type));
2691           break;
2692         }
2693       yaml_event_delete (&event);
2694     }
2695 
2696   return TRUE;
2697 }
2698 
2699 
2700 static gboolean
modulemd_module_stream_v2_parse_rpm_components(yaml_parser_t * parser,ModulemdModuleStreamV2 * modulestream,gboolean strict,GError ** error)2701 modulemd_module_stream_v2_parse_rpm_components (
2702   yaml_parser_t *parser,
2703   ModulemdModuleStreamV2 *modulestream,
2704   gboolean strict,
2705   GError **error)
2706 {
2707   MODULEMD_INIT_TRACE ();
2708   MMD_INIT_YAML_EVENT (event);
2709   gboolean done = FALSE;
2710   g_autoptr (GError) nested_error = NULL;
2711   g_autoptr (ModulemdComponentRpm) component = NULL;
2712 
2713   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2714 
2715   /* We *must* get a MAPPING_START here */
2716   YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
2717   if (event.type != YAML_MAPPING_START_EVENT)
2718     {
2719       MMD_YAML_ERROR_EVENT_EXIT_BOOL (
2720         error,
2721         event,
2722         "Got %s instead of MAPPING_START in rpm components.",
2723         mmd_yaml_get_event_name (event.type));
2724     }
2725 
2726   while (!done)
2727     {
2728       YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
2729 
2730       switch (event.type)
2731         {
2732         case YAML_MAPPING_END_EVENT: done = TRUE; break;
2733 
2734         case YAML_SCALAR_EVENT:
2735           component = modulemd_component_rpm_parse_yaml (
2736             parser,
2737             (const gchar *)event.data.scalar.value,
2738             strict,
2739             &nested_error);
2740           if (!component)
2741             {
2742               g_propagate_error (error, g_steal_pointer (&nested_error));
2743               return FALSE;
2744             }
2745           modulemd_module_stream_v2_add_component (
2746             modulestream, (ModulemdComponent *)component);
2747           g_clear_pointer (&component, g_object_unref);
2748           break;
2749 
2750         default:
2751           MMD_YAML_ERROR_EVENT_EXIT_BOOL (
2752             error,
2753             event,
2754             "Unexpected YAML event in RPM component: %s",
2755             mmd_yaml_get_event_name (event.type));
2756           break;
2757         }
2758       yaml_event_delete (&event);
2759     }
2760 
2761   return TRUE;
2762 }
2763 
2764 
2765 static gboolean
modulemd_module_stream_v2_parse_module_components(yaml_parser_t * parser,ModulemdModuleStreamV2 * modulestream,gboolean strict,GError ** error)2766 modulemd_module_stream_v2_parse_module_components (
2767   yaml_parser_t *parser,
2768   ModulemdModuleStreamV2 *modulestream,
2769   gboolean strict,
2770   GError **error)
2771 {
2772   MODULEMD_INIT_TRACE ();
2773   MMD_INIT_YAML_EVENT (event);
2774   gboolean done = FALSE;
2775   g_autoptr (GError) nested_error = NULL;
2776   g_autoptr (ModulemdComponentModule) component = NULL;
2777 
2778   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2779 
2780   /* We *must* get a MAPPING_START here */
2781   YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
2782   if (event.type != YAML_MAPPING_START_EVENT)
2783     {
2784       MMD_YAML_ERROR_EVENT_EXIT_BOOL (
2785         error,
2786         event,
2787         "Got %s instead of MAPPING_START in module components.",
2788         mmd_yaml_get_event_name (event.type));
2789     }
2790 
2791   while (!done)
2792     {
2793       YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
2794 
2795       switch (event.type)
2796         {
2797         case YAML_MAPPING_END_EVENT: done = TRUE; break;
2798 
2799         case YAML_SCALAR_EVENT:
2800           component = modulemd_component_module_parse_yaml (
2801             parser,
2802             (const gchar *)event.data.scalar.value,
2803             strict,
2804             &nested_error);
2805           if (!component)
2806             {
2807               g_propagate_error (error, g_steal_pointer (&nested_error));
2808               return FALSE;
2809             }
2810           modulemd_module_stream_v2_add_component (
2811             modulestream, (ModulemdComponent *)component);
2812           g_clear_pointer (&component, g_object_unref);
2813           break;
2814 
2815         default:
2816           MMD_YAML_ERROR_EVENT_EXIT_BOOL (
2817             error,
2818             event,
2819             "Unexpected YAML event in module component: %s",
2820             mmd_yaml_get_event_name (event.type));
2821           break;
2822         }
2823       yaml_event_delete (&event);
2824     }
2825 
2826   return TRUE;
2827 }
2828 
2829 
2830 static gboolean
2831 modulemd_module_stream_v2_parse_rpm_map (yaml_parser_t *parser,
2832                                          ModulemdModuleStreamV2 *modulestream,
2833                                          gboolean strict,
2834                                          GError **error);
2835 
2836 
2837 static gboolean
modulemd_module_stream_v2_parse_artifacts(yaml_parser_t * parser,ModulemdModuleStreamV2 * modulestream,gboolean strict,GError ** error)2838 modulemd_module_stream_v2_parse_artifacts (
2839   yaml_parser_t *parser,
2840   ModulemdModuleStreamV2 *modulestream,
2841   gboolean strict,
2842   GError **error)
2843 {
2844   MODULEMD_INIT_TRACE ();
2845   MMD_INIT_YAML_EVENT (event);
2846   gboolean done = FALSE;
2847   g_autoptr (GHashTable) set = NULL;
2848   g_autoptr (GError) nested_error = NULL;
2849 
2850   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2851 
2852   /* We *must* get a MAPPING_START here */
2853   YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
2854   if (event.type != YAML_MAPPING_START_EVENT)
2855     {
2856       MMD_YAML_ERROR_EVENT_EXIT_BOOL (
2857         error,
2858         event,
2859         "Got %s instead of MAPPING_START in artifacts.",
2860         mmd_yaml_get_event_name (event.type));
2861     }
2862 
2863   while (!done)
2864     {
2865       YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
2866 
2867       switch (event.type)
2868         {
2869         case YAML_MAPPING_END_EVENT: done = TRUE; break;
2870 
2871         case YAML_SCALAR_EVENT:
2872           if (g_str_equal ((const gchar *)event.data.scalar.value, "rpms"))
2873             {
2874               set = modulemd_yaml_parse_string_set (parser, &nested_error);
2875               if (!set)
2876                 {
2877                   g_propagate_error (error, g_steal_pointer (&nested_error));
2878                   return FALSE;
2879                 }
2880 
2881               modulemd_module_stream_v2_replace_rpm_artifacts (modulestream,
2882                                                                set);
2883               g_clear_pointer (&set, g_hash_table_unref);
2884             }
2885 
2886           else if (g_str_equal ((const gchar *)event.data.scalar.value,
2887                                 "rpm-map"))
2888             {
2889               if (!modulemd_module_stream_v2_parse_rpm_map (
2890                     parser, modulestream, strict, &nested_error))
2891                 {
2892                   g_propagate_error (error, g_steal_pointer (&nested_error));
2893                   return FALSE;
2894                 }
2895             }
2896 
2897           else
2898             {
2899               /* Encountered a key other than the expected ones. */
2900               SKIP_UNKNOWN (parser,
2901                             FALSE,
2902                             "Unexpected key in map: %s",
2903                             (const gchar *)event.data.scalar.value);
2904             }
2905 
2906           break;
2907 
2908         default:
2909           MMD_YAML_ERROR_EVENT_EXIT_BOOL (
2910             error, event, "Unexpected YAML event in map");
2911           break;
2912         }
2913       yaml_event_delete (&event);
2914     }
2915 
2916   return TRUE;
2917 }
2918 
2919 
2920 static gboolean
2921 modulemd_module_stream_v2_parse_rpm_map_digest (
2922   yaml_parser_t *parser,
2923   ModulemdModuleStreamV2 *modulestream,
2924   gboolean strict,
2925   const gchar *digest,
2926   GError **error);
2927 
2928 static gboolean
modulemd_module_stream_v2_parse_rpm_map(yaml_parser_t * parser,ModulemdModuleStreamV2 * modulestream,gboolean strict,GError ** error)2929 modulemd_module_stream_v2_parse_rpm_map (yaml_parser_t *parser,
2930                                          ModulemdModuleStreamV2 *modulestream,
2931                                          gboolean strict,
2932                                          GError **error)
2933 {
2934   MODULEMD_INIT_TRACE ();
2935   MMD_INIT_YAML_EVENT (event);
2936   gboolean done = FALSE;
2937   g_autoptr (GError) nested_error = NULL;
2938 
2939   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2940 
2941   /* We *must* get a MAPPING_START here */
2942   YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
2943   if (event.type != YAML_MAPPING_START_EVENT)
2944     {
2945       MMD_YAML_ERROR_EVENT_EXIT_BOOL (
2946         error,
2947         event,
2948         "Got %s instead of MAPPING_START in rpm-map.",
2949         mmd_yaml_get_event_name (event.type));
2950     }
2951 
2952   while (!done)
2953     {
2954       YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
2955 
2956       switch (event.type)
2957         {
2958         case YAML_MAPPING_END_EVENT: done = TRUE; break;
2959 
2960         case YAML_SCALAR_EVENT:
2961           /* Each entry in the map here represents a digest name */
2962           if (!modulemd_module_stream_v2_parse_rpm_map_digest (
2963                 parser,
2964                 modulestream,
2965                 strict,
2966                 (const gchar *)event.data.scalar.value,
2967                 &nested_error))
2968             {
2969               g_propagate_error (error, g_steal_pointer (&nested_error));
2970               return FALSE;
2971             }
2972           break;
2973 
2974         default:
2975           MMD_YAML_ERROR_EVENT_EXIT_BOOL (
2976             error, event, "Unexpected YAML event in map");
2977           break;
2978         }
2979       yaml_event_delete (&event);
2980     }
2981 
2982   return TRUE;
2983 }
2984 
2985 
2986 static gboolean
modulemd_module_stream_v2_parse_rpm_map_digest(yaml_parser_t * parser,ModulemdModuleStreamV2 * modulestream,gboolean strict,const gchar * digest,GError ** error)2987 modulemd_module_stream_v2_parse_rpm_map_digest (
2988   yaml_parser_t *parser,
2989   ModulemdModuleStreamV2 *modulestream,
2990   gboolean strict,
2991   const gchar *digest,
2992   GError **error)
2993 {
2994   MODULEMD_INIT_TRACE ();
2995   MMD_INIT_YAML_EVENT (event);
2996   gboolean done = FALSE;
2997   g_autoptr (GError) nested_error = NULL;
2998   const gchar *checksum = NULL;
2999   g_autoptr (ModulemdRpmMapEntry) entry = NULL;
3000 
3001   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
3002 
3003   /* We *must* get a MAPPING_START here */
3004   YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
3005   if (event.type != YAML_MAPPING_START_EVENT)
3006     {
3007       MMD_YAML_ERROR_EVENT_EXIT_BOOL (
3008         error,
3009         event,
3010         "Got %s instead of MAPPING_START in rpm-map.",
3011         mmd_yaml_get_event_name (event.type));
3012     }
3013 
3014   while (!done)
3015     {
3016       YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
3017 
3018       switch (event.type)
3019         {
3020         case YAML_MAPPING_END_EVENT: done = TRUE; break;
3021 
3022         case YAML_SCALAR_EVENT:
3023           /* Each key in this map is a checksum with the value being a
3024            * ModulemdRpmMapEntry
3025            */
3026           checksum = (const gchar *)event.data.scalar.value;
3027 
3028           entry =
3029             modulemd_rpm_map_entry_parse_yaml (parser, strict, &nested_error);
3030           if (!entry)
3031             {
3032               g_propagate_error (error, g_steal_pointer (&nested_error));
3033               return FALSE;
3034             }
3035 
3036           modulemd_module_stream_v2_set_rpm_artifact_map_entry (
3037             modulestream, entry, digest, checksum);
3038 
3039           g_clear_object (&entry);
3040           break;
3041 
3042         default:
3043           MMD_YAML_ERROR_EVENT_EXIT_BOOL (
3044             error, event, "Unexpected YAML event in map");
3045           break;
3046         }
3047       yaml_event_delete (&event);
3048     }
3049 
3050   return TRUE;
3051 }
3052 
3053 
3054 gboolean
3055 modulemd_module_stream_v2_emit_rpm_map (ModulemdModuleStreamV2 *self,
3056                                         yaml_emitter_t *emitter,
3057                                         GError **error);
3058 
3059 gboolean
modulemd_module_stream_v2_emit_yaml(ModulemdModuleStreamV2 * self,yaml_emitter_t * emitter,GError ** error)3060 modulemd_module_stream_v2_emit_yaml (ModulemdModuleStreamV2 *self,
3061                                      yaml_emitter_t *emitter,
3062                                      GError **error)
3063 {
3064   MODULEMD_INIT_TRACE ();
3065 
3066   if (!modulemd_module_stream_emit_yaml_base (
3067         MODULEMD_MODULE_STREAM (self), emitter, error))
3068     {
3069       return FALSE;
3070     }
3071 
3072   if (modulemd_module_stream_v2_is_static_context (self))
3073     {
3074       EMIT_KEY_VALUE (emitter, error, "static_context", "true");
3075     }
3076 
3077   EMIT_KEY_VALUE_IF_SET (
3078     emitter, error, "arch", modulemd_module_stream_v2_get_arch (self));
3079   EMIT_KEY_VALUE (emitter, error, "summary", self->summary);
3080   EMIT_KEY_VALUE_FULL (emitter,
3081                        error,
3082                        "description",
3083                        self->description,
3084                        YAML_FOLDED_SCALAR_STYLE);
3085 
3086   EMIT_HASHTABLE_VALUES_IF_NON_EMPTY (emitter,
3087                                       error,
3088                                       "servicelevels",
3089                                       self->servicelevels,
3090                                       modulemd_service_level_emit_yaml);
3091 
3092   if (!NON_EMPTY_TABLE (self->module_licenses))
3093     {
3094       g_set_error (error,
3095                    MODULEMD_YAML_ERROR,
3096                    MMD_YAML_ERROR_EMIT,
3097                    "Module licenses is not allowed to be empty");
3098       return FALSE;
3099     }
3100 
3101   EMIT_SCALAR (emitter, error, "license");
3102   EMIT_MAPPING_START (emitter, error);
3103   EMIT_STRING_SET (emitter, error, "module", self->module_licenses);
3104   EMIT_STRING_SET_IF_NON_EMPTY (
3105     emitter, error, "content", self->content_licenses);
3106   EMIT_MAPPING_END (emitter, error);
3107 
3108   if (self->xmd != NULL)
3109     {
3110       EMIT_SCALAR (emitter, error, "xmd");
3111       if (!modulemd_yaml_emit_variant (emitter, self->xmd, error))
3112         {
3113           return FALSE;
3114         }
3115     }
3116 
3117   EMIT_ARRAY_VALUES_IF_NON_EMPTY (emitter,
3118                                   error,
3119                                   "dependencies",
3120                                   self->dependencies,
3121                                   modulemd_dependencies_emit_yaml);
3122 
3123   if (self->community || self->documentation || self->tracker)
3124     {
3125       EMIT_SCALAR (emitter, error, "references");
3126       EMIT_MAPPING_START (emitter, error);
3127       EMIT_KEY_VALUE_IF_SET (emitter, error, "community", self->community);
3128       EMIT_KEY_VALUE_IF_SET (
3129         emitter, error, "documentation", self->documentation);
3130       EMIT_KEY_VALUE_IF_SET (emitter, error, "tracker", self->tracker);
3131       EMIT_MAPPING_END (emitter, error);
3132     }
3133 
3134   EMIT_HASHTABLE_VALUES_IF_NON_EMPTY (
3135     emitter, error, "profiles", self->profiles, modulemd_profile_emit_yaml);
3136 
3137   if (NON_EMPTY_TABLE (self->rpm_api))
3138     {
3139       EMIT_SCALAR (emitter, error, "api");
3140       EMIT_MAPPING_START (emitter, error);
3141       EMIT_STRING_SET (emitter, error, "rpms", self->rpm_api);
3142       EMIT_MAPPING_END (emitter, error);
3143     }
3144 
3145   if (NON_EMPTY_TABLE (self->rpm_filters))
3146     {
3147       EMIT_SCALAR (emitter, error, "filter");
3148       EMIT_MAPPING_START (emitter, error);
3149       EMIT_STRING_SET (emitter, error, "rpms", self->rpm_filters);
3150       EMIT_MAPPING_END (emitter, error);
3151     }
3152 
3153   if (NON_EMPTY_TABLE (self->demodularized_rpms))
3154     {
3155       EMIT_SCALAR (emitter, error, "demodularized");
3156       EMIT_MAPPING_START (emitter, error);
3157       EMIT_STRING_SET (emitter, error, "rpms", self->demodularized_rpms);
3158       EMIT_MAPPING_END (emitter, error);
3159     }
3160 
3161   if (self->buildopts != NULL)
3162     {
3163       EMIT_SCALAR (emitter, error, "buildopts");
3164       EMIT_MAPPING_START (emitter, error);
3165       if (!modulemd_buildopts_emit_yaml (self->buildopts, emitter, error))
3166         {
3167           return FALSE;
3168         }
3169       EMIT_MAPPING_END (emitter, error);
3170     }
3171 
3172   if (NON_EMPTY_TABLE (self->rpm_components) ||
3173       NON_EMPTY_TABLE (self->module_components))
3174     {
3175       EMIT_SCALAR (emitter, error, "components");
3176       EMIT_MAPPING_START (emitter, error);
3177       EMIT_HASHTABLE_VALUES_IF_NON_EMPTY (emitter,
3178                                           error,
3179                                           "rpms",
3180                                           self->rpm_components,
3181                                           modulemd_component_rpm_emit_yaml);
3182       EMIT_HASHTABLE_VALUES_IF_NON_EMPTY (emitter,
3183                                           error,
3184                                           "modules",
3185                                           self->module_components,
3186                                           modulemd_component_module_emit_yaml);
3187       EMIT_MAPPING_END (emitter, error);
3188     }
3189 
3190   if (NON_EMPTY_TABLE (self->rpm_artifacts) ||
3191       NON_EMPTY_TABLE (self->rpm_artifact_map))
3192     {
3193       EMIT_SCALAR (emitter, error, "artifacts");
3194       EMIT_MAPPING_START (emitter, error);
3195 
3196       /* Emit the rpm artifacts */
3197       EMIT_STRING_SET_IF_NON_EMPTY (
3198         emitter, error, "rpms", self->rpm_artifacts);
3199 
3200       /* Emit the rpm-map */
3201       if (!modulemd_module_stream_v2_emit_rpm_map (self, emitter, error))
3202         {
3203           return FALSE;
3204         }
3205 
3206       EMIT_MAPPING_END (emitter, error);
3207     }
3208 
3209   /* The "data" mapping */
3210   EMIT_MAPPING_END (emitter, error);
3211   /* The overall document mapping */
3212   EMIT_MAPPING_END (emitter, error);
3213   if (!mmd_emitter_end_document (emitter, error))
3214     {
3215       return FALSE;
3216     }
3217 
3218   return TRUE;
3219 }
3220 
3221 
3222 gboolean
modulemd_module_stream_v2_emit_rpm_map(ModulemdModuleStreamV2 * self,yaml_emitter_t * emitter,GError ** error)3223 modulemd_module_stream_v2_emit_rpm_map (ModulemdModuleStreamV2 *self,
3224                                         yaml_emitter_t *emitter,
3225                                         GError **error)
3226 {
3227   GHashTable *digest_table = NULL;
3228   g_autoptr (GPtrArray) digests = NULL;
3229   const gchar *digest = NULL;
3230   g_autoptr (GPtrArray) checksums = NULL;
3231   const gchar *checksum = NULL;
3232   ModulemdRpmMapEntry *entry = NULL;
3233 
3234   if (!NON_EMPTY_TABLE (self->rpm_artifact_map))
3235     {
3236       /* Nothing to output here */
3237       return TRUE;
3238     }
3239 
3240   digests =
3241     modulemd_ordered_str_keys (self->rpm_artifact_map, modulemd_strcmp_sort);
3242 
3243   EMIT_SCALAR (emitter, error, "rpm-map");
3244   EMIT_MAPPING_START (emitter, error);
3245 
3246   for (guint i = 0; i < digests->len; i++)
3247     {
3248       digest = g_ptr_array_index (digests, i);
3249       EMIT_SCALAR (emitter, error, digest);
3250 
3251       digest_table = g_hash_table_lookup (self->rpm_artifact_map, digest);
3252 
3253       EMIT_MAPPING_START (emitter, error);
3254 
3255       checksums =
3256         modulemd_ordered_str_keys (digest_table, modulemd_strcmp_sort);
3257 
3258       for (guint j = 0; j < digests->len; j++)
3259         {
3260           checksum = g_ptr_array_index (checksums, j);
3261           EMIT_SCALAR (emitter, error, checksum);
3262 
3263           entry = g_hash_table_lookup (digest_table, checksum);
3264 
3265           if (!modulemd_rpm_map_entry_emit_yaml (entry, emitter, error))
3266             {
3267               return FALSE;
3268             }
3269         }
3270 
3271       EMIT_MAPPING_END (emitter, error);
3272 
3273       g_clear_pointer (&checksums, g_ptr_array_unref);
3274     }
3275 
3276   EMIT_MAPPING_END (emitter, error);
3277 
3278   return TRUE;
3279 }
3280