1 /*
2  * This file is part of libmodulemd
3  * Copyright (C) 2020 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 "private/modulemd-build-config-private.h"
15 #include "private/modulemd-component-private.h"
16 #include "private/modulemd-component-module-private.h"
17 #include "private/modulemd-component-rpm-private.h"
18 #include "private/modulemd-defaults-v1-private.h"
19 #include "private/modulemd-module-stream-private.h"
20 #include "private/modulemd-packager-v3-private.h"
21 #include "private/modulemd-profile-private.h"
22 #include "private/modulemd-subdocument-info-private.h"
23 #include "private/modulemd-util.h"
24 #include "private/modulemd-yaml.h"
25 
26 struct _ModulemdPackagerV3
27 {
28   GObject parent_instance;
29 
30   gchar *module_name;
31   gchar *stream_name;
32   gchar *summary;
33   gchar *description;
34   GHashTable *module_licenses; /* string set */
35   GVariant *xmd;
36   GHashTable *build_configs; /* <string, Modulemd.BuildConfig> */
37   gchar *community;
38   gchar *documentation;
39   gchar *tracker;
40   GHashTable *profiles; /* <string, Modulemd.Profile> */
41   GHashTable *rpm_api; /* string set */
42   GHashTable *rpm_filters; /* string set */
43   GHashTable *demodularized_rpms; /* string set */
44   GHashTable *rpm_components; /* <string, Modulemd.ComponentRpm> */
45   GHashTable *module_components; /* <string, Modulemd.ComponentModule */
46 };
47 
G_DEFINE_TYPE(ModulemdPackagerV3,modulemd_packager_v3,G_TYPE_OBJECT)48 G_DEFINE_TYPE (ModulemdPackagerV3, modulemd_packager_v3, G_TYPE_OBJECT)
49 
50 ModulemdPackagerV3 *
51 modulemd_packager_v3_new (void)
52 {
53   return g_object_new (MODULEMD_TYPE_PACKAGER_V3, NULL);
54 }
55 
56 static void
modulemd_packager_v3_finalize(GObject * object)57 modulemd_packager_v3_finalize (GObject *object)
58 {
59   ModulemdPackagerV3 *self = (ModulemdPackagerV3 *)object;
60 
61   g_clear_pointer (&self->module_name, g_free);
62   g_clear_pointer (&self->stream_name, g_free);
63   g_clear_pointer (&self->summary, g_free);
64   g_clear_pointer (&self->description, g_free);
65   g_clear_pointer (&self->module_licenses, g_hash_table_unref);
66   g_clear_pointer (&self->xmd, g_variant_unref);
67   g_clear_pointer (&self->build_configs, g_hash_table_unref);
68   g_clear_pointer (&self->community, g_free);
69   g_clear_pointer (&self->documentation, g_free);
70   g_clear_pointer (&self->tracker, g_free);
71   g_clear_pointer (&self->profiles, g_hash_table_unref);
72   g_clear_pointer (&self->rpm_api, g_hash_table_unref);
73   g_clear_pointer (&self->rpm_filters, g_hash_table_unref);
74   g_clear_pointer (&self->demodularized_rpms, g_hash_table_unref);
75   g_clear_pointer (&self->rpm_components, g_hash_table_unref);
76   g_clear_pointer (&self->module_components, g_hash_table_unref);
77 
78   G_OBJECT_CLASS (modulemd_packager_v3_parent_class)->finalize (object);
79 }
80 
81 static void
modulemd_packager_v3_class_init(ModulemdPackagerV3Class * klass)82 modulemd_packager_v3_class_init (ModulemdPackagerV3Class *klass)
83 {
84   GObjectClass *object_class = G_OBJECT_CLASS (klass);
85 
86   object_class->finalize = modulemd_packager_v3_finalize;
87 }
88 
89 static void
modulemd_packager_v3_init(ModulemdPackagerV3 * self)90 modulemd_packager_v3_init (ModulemdPackagerV3 *self)
91 {
92   self->module_licenses =
93     g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
94 
95   self->build_configs =
96     g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
97 
98   self->profiles =
99     g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
100 
101   self->rpm_api =
102     g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
103 
104   self->rpm_filters =
105     g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
106 
107   self->demodularized_rpms =
108     g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
109 
110   self->rpm_components =
111     g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
112 
113   self->module_components =
114     g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
115 }
116 
117 
118 ModulemdPackagerV3 *
modulemd_packager_v3_copy(ModulemdPackagerV3 * self)119 modulemd_packager_v3_copy (ModulemdPackagerV3 *self)
120 {
121   g_autoptr (ModulemdPackagerV3) copy = modulemd_packager_v3_new ();
122 
123   modulemd_packager_v3_set_module_name (
124     copy, modulemd_packager_v3_get_module_name (self));
125 
126   modulemd_packager_v3_set_stream_name (
127     copy, modulemd_packager_v3_get_stream_name (self));
128 
129   modulemd_packager_v3_set_summary (copy,
130                                     modulemd_packager_v3_get_summary (self));
131 
132   modulemd_packager_v3_set_description (
133     copy, modulemd_packager_v3_get_description (self));
134 
135   MODULEMD_REPLACE_SET (copy->module_licenses, self->module_licenses);
136 
137   modulemd_packager_v3_set_xmd (copy, modulemd_packager_v3_get_xmd (self));
138 
139   COPY_HASHTABLE_BY_VALUE_ADDER (
140     copy, self, build_configs, modulemd_packager_v3_add_build_config);
141 
142   modulemd_packager_v3_set_community (
143     copy, modulemd_packager_v3_get_community (self));
144 
145   modulemd_packager_v3_set_documentation (
146     copy, modulemd_packager_v3_get_documentation (self));
147 
148   modulemd_packager_v3_set_tracker (copy,
149                                     modulemd_packager_v3_get_tracker (self));
150 
151   COPY_HASHTABLE_BY_VALUE_ADDER (
152     copy, self, profiles, modulemd_packager_v3_add_profile);
153 
154   modulemd_packager_v3_replace_rpm_api (copy, self->rpm_api);
155 
156   modulemd_packager_v3_replace_rpm_filters (copy, self->rpm_filters);
157 
158   modulemd_packager_v3_replace_demodularized_rpms (copy,
159                                                    self->demodularized_rpms);
160 
161   COPY_HASHTABLE_BY_VALUE_ADDER (
162     copy, self, rpm_components, modulemd_packager_v3_add_component);
163 
164   COPY_HASHTABLE_BY_VALUE_ADDER (
165     copy, self, module_components, modulemd_packager_v3_add_component);
166 
167   return g_steal_pointer (&copy);
168 }
169 
170 
171 void
modulemd_packager_v3_set_module_name(ModulemdPackagerV3 * self,const gchar * module_name)172 modulemd_packager_v3_set_module_name (ModulemdPackagerV3 *self,
173                                       const gchar *module_name)
174 {
175   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
176 
177   g_clear_pointer (&self->module_name, g_free);
178 
179   if (module_name)
180     {
181       self->module_name = g_strdup (module_name);
182     }
183 }
184 
185 
186 const gchar *
modulemd_packager_v3_get_module_name(ModulemdPackagerV3 * self)187 modulemd_packager_v3_get_module_name (ModulemdPackagerV3 *self)
188 {
189   g_return_val_if_fail (MODULEMD_IS_PACKAGER_V3 (self), NULL);
190 
191   return self->module_name;
192 }
193 
194 
195 void
modulemd_packager_v3_set_stream_name(ModulemdPackagerV3 * self,const gchar * stream_name)196 modulemd_packager_v3_set_stream_name (ModulemdPackagerV3 *self,
197                                       const gchar *stream_name)
198 {
199   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
200 
201   g_clear_pointer (&self->stream_name, g_free);
202 
203   if (stream_name)
204     {
205       self->stream_name = g_strdup (stream_name);
206     }
207 }
208 
209 
210 const gchar *
modulemd_packager_v3_get_stream_name(ModulemdPackagerV3 * self)211 modulemd_packager_v3_get_stream_name (ModulemdPackagerV3 *self)
212 {
213   g_return_val_if_fail (MODULEMD_IS_PACKAGER_V3 (self), NULL);
214 
215   return self->stream_name;
216 }
217 
218 
219 void
modulemd_packager_v3_set_summary(ModulemdPackagerV3 * self,const gchar * summary)220 modulemd_packager_v3_set_summary (ModulemdPackagerV3 *self,
221                                   const gchar *summary)
222 {
223   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
224 
225   g_clear_pointer (&self->summary, g_free);
226 
227   if (summary)
228     {
229       self->summary = g_strdup (summary);
230     }
231 }
232 
233 
234 const gchar *
modulemd_packager_v3_get_summary(ModulemdPackagerV3 * self)235 modulemd_packager_v3_get_summary (ModulemdPackagerV3 *self)
236 {
237   g_return_val_if_fail (MODULEMD_IS_PACKAGER_V3 (self), NULL);
238 
239   return self->summary;
240 }
241 
242 
243 void
modulemd_packager_v3_set_description(ModulemdPackagerV3 * self,const gchar * description)244 modulemd_packager_v3_set_description (ModulemdPackagerV3 *self,
245                                       const gchar *description)
246 {
247   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
248 
249   g_clear_pointer (&self->description, g_free);
250 
251   if (description)
252     {
253       self->description = g_strdup (description);
254     }
255 }
256 
257 
258 const gchar *
modulemd_packager_v3_get_description(ModulemdPackagerV3 * self)259 modulemd_packager_v3_get_description (ModulemdPackagerV3 *self)
260 {
261   g_return_val_if_fail (MODULEMD_IS_PACKAGER_V3 (self), NULL);
262 
263   return self->description;
264 }
265 
266 
267 void
modulemd_packager_v3_add_module_license(ModulemdPackagerV3 * self,const gchar * license)268 modulemd_packager_v3_add_module_license (ModulemdPackagerV3 *self,
269                                          const gchar *license)
270 {
271   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
272 
273   if (!license)
274     {
275       return;
276     }
277 
278   g_hash_table_add (self->module_licenses, g_strdup (license));
279 }
280 
281 
282 void
modulemd_packager_v3_remove_module_license(ModulemdPackagerV3 * self,const gchar * license)283 modulemd_packager_v3_remove_module_license (ModulemdPackagerV3 *self,
284                                             const gchar *license)
285 {
286   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
287 
288   if (!license)
289     {
290       return;
291     }
292 
293   g_hash_table_remove (self->module_licenses, license);
294 }
295 
296 
297 void
modulemd_packager_v3_clear_module_licenses(ModulemdPackagerV3 * self)298 modulemd_packager_v3_clear_module_licenses (ModulemdPackagerV3 *self)
299 {
300   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
301 
302   g_hash_table_remove_all (self->module_licenses);
303 }
304 
305 
306 GStrv
modulemd_packager_v3_get_module_licenses_as_strv(ModulemdPackagerV3 * self)307 modulemd_packager_v3_get_module_licenses_as_strv (ModulemdPackagerV3 *self)
308 {
309   g_return_val_if_fail (MODULEMD_IS_PACKAGER_V3 (self), NULL);
310 
311   return modulemd_ordered_str_keys_as_strv (self->module_licenses);
312 }
313 
314 
315 void
modulemd_packager_v3_set_xmd(ModulemdPackagerV3 * self,GVariant * xmd)316 modulemd_packager_v3_set_xmd (ModulemdPackagerV3 *self, GVariant *xmd)
317 {
318   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
319 
320   /* Do nothing if we were passed the same pointer */
321   if (self->xmd == xmd)
322     {
323       return;
324     }
325 
326   g_clear_pointer (&self->xmd, g_variant_unref);
327   self->xmd = modulemd_variant_deep_copy (xmd);
328 }
329 
330 GVariant *
modulemd_packager_v3_get_xmd(ModulemdPackagerV3 * self)331 modulemd_packager_v3_get_xmd (ModulemdPackagerV3 *self)
332 {
333   g_return_val_if_fail (MODULEMD_IS_PACKAGER_V3 (self), NULL);
334   return self->xmd;
335 }
336 
337 
338 guint64
modulemd_packager_v3_get_mdversion(ModulemdPackagerV3 * self)339 modulemd_packager_v3_get_mdversion (ModulemdPackagerV3 *self)
340 {
341   return MD_PACKAGER_VERSION_THREE;
342 }
343 
344 
345 void
modulemd_packager_v3_add_build_config(ModulemdPackagerV3 * self,ModulemdBuildConfig * buildconfig)346 modulemd_packager_v3_add_build_config (ModulemdPackagerV3 *self,
347                                        ModulemdBuildConfig *buildconfig)
348 {
349   if (!buildconfig)
350     return;
351 
352   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
353   g_return_if_fail (MODULEMD_IS_BUILD_CONFIG (buildconfig));
354 
355   g_hash_table_replace (
356     self->build_configs,
357     g_strdup (modulemd_build_config_get_context (buildconfig)),
358     modulemd_build_config_copy (buildconfig));
359 }
360 
361 
362 void
modulemd_packager_v3_clear_build_configs(ModulemdPackagerV3 * self)363 modulemd_packager_v3_clear_build_configs (ModulemdPackagerV3 *self)
364 {
365   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
366   g_hash_table_remove_all (self->build_configs);
367 }
368 
369 
370 GStrv
modulemd_packager_v3_get_build_config_contexts_as_strv(ModulemdPackagerV3 * self)371 modulemd_packager_v3_get_build_config_contexts_as_strv (
372   ModulemdPackagerV3 *self)
373 {
374   g_return_val_if_fail (MODULEMD_IS_PACKAGER_V3 (self), NULL);
375 
376   return modulemd_ordered_str_keys_as_strv (self->build_configs);
377 }
378 
379 
380 ModulemdBuildConfig *
modulemd_packager_v3_get_build_config(ModulemdPackagerV3 * self,const gchar * context)381 modulemd_packager_v3_get_build_config (ModulemdPackagerV3 *self,
382                                        const gchar *context)
383 {
384   g_return_val_if_fail (MODULEMD_IS_PACKAGER_V3 (self), NULL);
385 
386   return g_hash_table_lookup (self->build_configs, context);
387 }
388 
389 void
modulemd_packager_v3_set_community(ModulemdPackagerV3 * self,const gchar * community)390 modulemd_packager_v3_set_community (ModulemdPackagerV3 *self,
391                                     const gchar *community)
392 {
393   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
394 
395   g_clear_pointer (&self->community, g_free);
396 
397   if (community)
398     {
399       self->community = g_strdup (community);
400     }
401 }
402 
403 
404 const gchar *
modulemd_packager_v3_get_community(ModulemdPackagerV3 * self)405 modulemd_packager_v3_get_community (ModulemdPackagerV3 *self)
406 {
407   g_return_val_if_fail (MODULEMD_IS_PACKAGER_V3 (self), NULL);
408 
409   return self->community;
410 }
411 
412 
413 void
modulemd_packager_v3_set_documentation(ModulemdPackagerV3 * self,const gchar * documentation)414 modulemd_packager_v3_set_documentation (ModulemdPackagerV3 *self,
415                                         const gchar *documentation)
416 {
417   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
418 
419   g_clear_pointer (&self->documentation, g_free);
420 
421   if (documentation)
422     {
423       self->documentation = g_strdup (documentation);
424     }
425 }
426 
427 
428 const gchar *
modulemd_packager_v3_get_documentation(ModulemdPackagerV3 * self)429 modulemd_packager_v3_get_documentation (ModulemdPackagerV3 *self)
430 {
431   g_return_val_if_fail (MODULEMD_IS_PACKAGER_V3 (self), NULL);
432 
433   return self->documentation;
434 }
435 
436 
437 void
modulemd_packager_v3_set_tracker(ModulemdPackagerV3 * self,const gchar * tracker)438 modulemd_packager_v3_set_tracker (ModulemdPackagerV3 *self,
439                                   const gchar *tracker)
440 {
441   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
442 
443   g_clear_pointer (&self->tracker, g_free);
444 
445   if (tracker)
446     {
447       self->tracker = g_strdup (tracker);
448     }
449 }
450 
451 
452 const gchar *
modulemd_packager_v3_get_tracker(ModulemdPackagerV3 * self)453 modulemd_packager_v3_get_tracker (ModulemdPackagerV3 *self)
454 {
455   g_return_val_if_fail (MODULEMD_IS_PACKAGER_V3 (self), NULL);
456 
457   return self->tracker;
458 }
459 
460 
461 void
modulemd_packager_v3_add_profile(ModulemdPackagerV3 * self,ModulemdProfile * profile)462 modulemd_packager_v3_add_profile (ModulemdPackagerV3 *self,
463                                   ModulemdProfile *profile)
464 {
465   if (!profile)
466     {
467       return;
468     }
469   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
470   g_return_if_fail (MODULEMD_IS_PROFILE (profile));
471 
472   ModulemdProfile *copied_profile = modulemd_profile_copy (profile);
473 
474   g_hash_table_replace (self->profiles,
475                         g_strdup (modulemd_profile_get_name (profile)),
476                         copied_profile);
477 }
478 
479 
480 void
modulemd_packager_v3_clear_profiles(ModulemdPackagerV3 * self)481 modulemd_packager_v3_clear_profiles (ModulemdPackagerV3 *self)
482 {
483   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
484 
485   g_hash_table_remove_all (self->profiles);
486 }
487 
488 
489 GStrv
modulemd_packager_v3_get_profile_names_as_strv(ModulemdPackagerV3 * self)490 modulemd_packager_v3_get_profile_names_as_strv (ModulemdPackagerV3 *self)
491 {
492   g_return_val_if_fail (MODULEMD_IS_PACKAGER_V3 (self), NULL);
493 
494   return modulemd_ordered_str_keys_as_strv (self->profiles);
495 }
496 
497 
498 ModulemdProfile *
modulemd_packager_v3_get_profile(ModulemdPackagerV3 * self,const gchar * profile_name)499 modulemd_packager_v3_get_profile (ModulemdPackagerV3 *self,
500                                   const gchar *profile_name)
501 {
502   g_return_val_if_fail (MODULEMD_IS_PACKAGER_V3 (self), NULL);
503 
504   return g_hash_table_lookup (self->profiles, profile_name);
505 }
506 
507 
508 void
modulemd_packager_v3_add_rpm_api(ModulemdPackagerV3 * self,const gchar * rpm)509 modulemd_packager_v3_add_rpm_api (ModulemdPackagerV3 *self, const gchar *rpm)
510 {
511   if (!rpm)
512     {
513       return;
514     }
515 
516   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
517 
518   g_hash_table_add (self->rpm_api, g_strdup (rpm));
519 }
520 
521 
522 void
modulemd_packager_v3_replace_rpm_api(ModulemdPackagerV3 * self,GHashTable * set)523 modulemd_packager_v3_replace_rpm_api (ModulemdPackagerV3 *self,
524                                       GHashTable *set)
525 {
526   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
527 
528   MODULEMD_REPLACE_SET (self->rpm_api, set);
529 }
530 
531 
532 void
modulemd_packager_v3_remove_rpm_api(ModulemdPackagerV3 * self,const gchar * rpm)533 modulemd_packager_v3_remove_rpm_api (ModulemdPackagerV3 *self,
534                                      const gchar *rpm)
535 {
536   if (!rpm)
537     {
538       return;
539     }
540 
541   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
542 
543   g_hash_table_remove (self->rpm_api, rpm);
544 }
545 
546 
547 void
modulemd_packager_v3_clear_rpm_api(ModulemdPackagerV3 * self)548 modulemd_packager_v3_clear_rpm_api (ModulemdPackagerV3 *self)
549 {
550   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
551 
552   g_hash_table_remove_all (self->rpm_api);
553 }
554 
555 
556 GStrv
modulemd_packager_v3_get_rpm_api_as_strv(ModulemdPackagerV3 * self)557 modulemd_packager_v3_get_rpm_api_as_strv (ModulemdPackagerV3 *self)
558 {
559   g_return_val_if_fail (MODULEMD_IS_PACKAGER_V3 (self), NULL);
560 
561   return modulemd_ordered_str_keys_as_strv (self->rpm_api);
562 }
563 
564 void
modulemd_packager_v3_add_rpm_filter(ModulemdPackagerV3 * self,const gchar * rpm)565 modulemd_packager_v3_add_rpm_filter (ModulemdPackagerV3 *self,
566                                      const gchar *rpm)
567 {
568   if (!rpm)
569     {
570       return;
571     }
572 
573   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
574 
575   g_hash_table_add (self->rpm_filters, g_strdup (rpm));
576 }
577 
578 
579 void
modulemd_packager_v3_replace_rpm_filters(ModulemdPackagerV3 * self,GHashTable * set)580 modulemd_packager_v3_replace_rpm_filters (ModulemdPackagerV3 *self,
581                                           GHashTable *set)
582 {
583   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
584 
585   MODULEMD_REPLACE_SET (self->rpm_filters, set);
586 }
587 
588 
589 void
modulemd_packager_v3_remove_rpm_filter(ModulemdPackagerV3 * self,const gchar * rpm)590 modulemd_packager_v3_remove_rpm_filter (ModulemdPackagerV3 *self,
591                                         const gchar *rpm)
592 {
593   if (!rpm)
594     {
595       return;
596     }
597 
598   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
599 
600   g_hash_table_remove (self->rpm_filters, rpm);
601 }
602 
603 
604 void
modulemd_packager_v3_clear_rpm_filters(ModulemdPackagerV3 * self)605 modulemd_packager_v3_clear_rpm_filters (ModulemdPackagerV3 *self)
606 {
607   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
608 
609   g_hash_table_remove_all (self->rpm_filters);
610 }
611 
612 
613 GStrv
modulemd_packager_v3_get_rpm_filters_as_strv(ModulemdPackagerV3 * self)614 modulemd_packager_v3_get_rpm_filters_as_strv (ModulemdPackagerV3 *self)
615 {
616   g_return_val_if_fail (MODULEMD_IS_PACKAGER_V3 (self), NULL);
617 
618   return modulemd_ordered_str_keys_as_strv (self->rpm_filters);
619 }
620 
621 
622 void
modulemd_packager_v3_add_demodularized_rpm(ModulemdPackagerV3 * self,const gchar * rpm)623 modulemd_packager_v3_add_demodularized_rpm (ModulemdPackagerV3 *self,
624                                             const gchar *rpm)
625 {
626   if (!rpm)
627     {
628       return;
629     }
630 
631   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
632 
633   g_hash_table_add (self->demodularized_rpms, g_strdup (rpm));
634 }
635 
636 
637 void
modulemd_packager_v3_replace_demodularized_rpms(ModulemdPackagerV3 * self,GHashTable * set)638 modulemd_packager_v3_replace_demodularized_rpms (ModulemdPackagerV3 *self,
639                                                  GHashTable *set)
640 {
641   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
642 
643   MODULEMD_REPLACE_SET (self->demodularized_rpms, set);
644 }
645 
646 
647 void
modulemd_packager_v3_remove_demodularized_rpm(ModulemdPackagerV3 * self,const gchar * rpm)648 modulemd_packager_v3_remove_demodularized_rpm (ModulemdPackagerV3 *self,
649                                                const gchar *rpm)
650 {
651   if (!rpm)
652     {
653       return;
654     }
655 
656   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
657 
658   g_hash_table_remove (self->demodularized_rpms, rpm);
659 }
660 
661 
662 void
modulemd_packager_v3_clear_demodularized_rpms(ModulemdPackagerV3 * self)663 modulemd_packager_v3_clear_demodularized_rpms (ModulemdPackagerV3 *self)
664 {
665   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
666 
667   g_hash_table_remove_all (self->demodularized_rpms);
668 }
669 
670 
671 GStrv
modulemd_packager_v3_get_demodularized_rpms(ModulemdPackagerV3 * self)672 modulemd_packager_v3_get_demodularized_rpms (ModulemdPackagerV3 *self)
673 {
674   g_return_val_if_fail (MODULEMD_IS_PACKAGER_V3 (self), NULL);
675 
676   return modulemd_ordered_str_keys_as_strv (self->demodularized_rpms);
677 }
678 
679 
680 void
modulemd_packager_v3_add_component(ModulemdPackagerV3 * self,ModulemdComponent * component)681 modulemd_packager_v3_add_component (ModulemdPackagerV3 *self,
682                                     ModulemdComponent *component)
683 {
684   GHashTable *table = NULL;
685 
686   /* Do nothing if we were passed a NULL component */
687   if (!component)
688     {
689       return;
690     }
691 
692   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
693   g_return_if_fail (MODULEMD_IS_COMPONENT (component));
694 
695   if (MODULEMD_IS_COMPONENT_RPM (component))
696     {
697       table = self->rpm_components;
698     }
699   else if (MODULEMD_IS_COMPONENT_MODULE (component))
700     {
701       table = self->module_components;
702     }
703   else
704     {
705       /* Unknown component. Raise a warning and return */
706       g_return_if_reached ();
707     }
708 
709   /* Add the component to the table. This will replace an existing component
710    * with the same name
711    */
712   g_hash_table_replace (table,
713                         g_strdup (modulemd_component_get_key (component)),
714                         modulemd_component_copy (component, NULL));
715 }
716 
717 
718 void
modulemd_packager_v3_remove_module_component(ModulemdPackagerV3 * self,const gchar * component_name)719 modulemd_packager_v3_remove_module_component (ModulemdPackagerV3 *self,
720                                               const gchar *component_name)
721 {
722   /* Do nothing if we were passed a NULL component_name */
723   if (!component_name)
724     {
725       return;
726     }
727 
728   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
729 
730   g_hash_table_remove (self->module_components, component_name);
731 }
732 
733 
734 void
modulemd_packager_v3_clear_module_components(ModulemdPackagerV3 * self)735 modulemd_packager_v3_clear_module_components (ModulemdPackagerV3 *self)
736 {
737   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
738 
739   g_hash_table_remove_all (self->module_components);
740 }
741 
742 
743 void
modulemd_packager_v3_remove_rpm_component(ModulemdPackagerV3 * self,const gchar * component_name)744 modulemd_packager_v3_remove_rpm_component (ModulemdPackagerV3 *self,
745                                            const gchar *component_name)
746 {
747   /* Do nothing if we were passed a NULL component_name */
748   if (!component_name)
749     {
750       return;
751     }
752 
753   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
754 
755   g_hash_table_remove (self->rpm_components, component_name);
756 }
757 
758 
759 void
modulemd_packager_v3_clear_rpm_components(ModulemdPackagerV3 * self)760 modulemd_packager_v3_clear_rpm_components (ModulemdPackagerV3 *self)
761 {
762   g_return_if_fail (MODULEMD_IS_PACKAGER_V3 (self));
763 
764   g_hash_table_remove_all (self->rpm_components);
765 }
766 
767 
768 GStrv
modulemd_packager_v3_get_module_component_names_as_strv(ModulemdPackagerV3 * self)769 modulemd_packager_v3_get_module_component_names_as_strv (
770   ModulemdPackagerV3 *self)
771 {
772   g_return_val_if_fail (MODULEMD_IS_PACKAGER_V3 (self), NULL);
773 
774   return modulemd_ordered_str_keys_as_strv (self->module_components);
775 }
776 
777 
778 GStrv
modulemd_packager_v3_get_rpm_component_names_as_strv(ModulemdPackagerV3 * self)779 modulemd_packager_v3_get_rpm_component_names_as_strv (ModulemdPackagerV3 *self)
780 {
781   g_return_val_if_fail (MODULEMD_IS_PACKAGER_V3 (self), NULL);
782 
783   return modulemd_ordered_str_keys_as_strv (self->rpm_components);
784 }
785 
786 
787 ModulemdComponentModule *
modulemd_packager_v3_get_module_component(ModulemdPackagerV3 * self,const gchar * component_name)788 modulemd_packager_v3_get_module_component (ModulemdPackagerV3 *self,
789                                            const gchar *component_name)
790 {
791   g_return_val_if_fail (MODULEMD_IS_PACKAGER_V3 (self), NULL);
792 
793   return g_hash_table_lookup (self->module_components, component_name);
794 }
795 
796 
797 ModulemdComponentRpm *
modulemd_packager_v3_get_rpm_component(ModulemdPackagerV3 * self,const gchar * component_name)798 modulemd_packager_v3_get_rpm_component (ModulemdPackagerV3 *self,
799                                         const gchar *component_name)
800 {
801   g_return_val_if_fail (MODULEMD_IS_PACKAGER_V3 (self), NULL);
802 
803   return g_hash_table_lookup (self->rpm_components, component_name);
804 }
805 
806 
807 gboolean
modulemd_packager_v3_to_defaults(ModulemdPackagerV3 * self,ModulemdDefaults ** defaults_ptr,GError ** error)808 modulemd_packager_v3_to_defaults (ModulemdPackagerV3 *self,
809                                   ModulemdDefaults **defaults_ptr,
810                                   GError **error)
811 {
812   g_autoptr (ModulemdDefaultsV1) defaults = NULL;
813   ModulemdProfile *profile;
814   g_autoptr (GError) nested_error = NULL;
815   GHashTableIter iter;
816   gpointer value;
817 
818   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
819   g_return_val_if_fail (defaults_ptr == NULL || *defaults_ptr == NULL, FALSE);
820   g_return_val_if_fail (MODULEMD_IS_PACKAGER_V3 (self), FALSE);
821 
822   g_hash_table_iter_init (&iter, self->profiles);
823   while (g_hash_table_iter_next (&iter, NULL, &value))
824     {
825       profile = MODULEMD_PROFILE (value);
826       if (modulemd_profile_is_default (profile))
827         {
828           if (!defaults)
829             {
830               defaults = modulemd_defaults_v1_new (self->module_name);
831             }
832           modulemd_defaults_v1_add_default_profile_for_stream (
833             defaults,
834             self->stream_name,
835             modulemd_profile_get_name (profile),
836             NULL);
837         }
838     }
839 
840   if (!defaults)
841     {
842       return TRUE;
843     }
844 
845   if (!modulemd_defaults_validate (MODULEMD_DEFAULTS (defaults),
846                                    &nested_error))
847     {
848       g_propagate_error (error, g_steal_pointer (&nested_error));
849       return FALSE;
850     }
851 
852   *defaults_ptr = MODULEMD_DEFAULTS (g_steal_pointer (&defaults));
853   return TRUE;
854 }
855 
856 
857 static void
copy_packager_v3_common_to_stream_v2(ModulemdModuleStreamV2 * stream_v2,ModulemdPackagerV3 * packager_v3)858 copy_packager_v3_common_to_stream_v2 (ModulemdModuleStreamV2 *stream_v2,
859                                       ModulemdPackagerV3 *packager_v3)
860 {
861   g_autoptr (ModulemdProfile) profile = NULL;
862   GHashTableIter iter;
863   gpointer value;
864 
865   modulemd_module_stream_v2_set_summary (
866     stream_v2, modulemd_packager_v3_get_summary (packager_v3));
867 
868   modulemd_module_stream_v2_set_description (
869     stream_v2, modulemd_packager_v3_get_description (packager_v3));
870 
871   /* Packager v3 "license" is optional. Stream v2 "license" is required
872    * Fill in the default Packager v3 license if none has been specified.
873    */
874   if (g_hash_table_size (packager_v3->module_licenses) == 0)
875     {
876       modulemd_module_stream_v2_add_module_license (
877         stream_v2, MMD_PACKAGER_DEFAULT_MODULE_LICENSE);
878     }
879   else
880     {
881       MODULEMD_REPLACE_SET (stream_v2->module_licenses,
882                             packager_v3->module_licenses);
883     }
884 
885   modulemd_module_stream_v2_set_xmd (
886     stream_v2, modulemd_packager_v3_get_xmd (packager_v3));
887 
888   modulemd_module_stream_v2_set_community (
889     stream_v2, modulemd_packager_v3_get_community (packager_v3));
890 
891   modulemd_module_stream_v2_set_documentation (
892     stream_v2, modulemd_packager_v3_get_documentation (packager_v3));
893 
894   modulemd_module_stream_v2_set_tracker (
895     stream_v2, modulemd_packager_v3_get_tracker (packager_v3));
896 
897   g_hash_table_iter_init (&iter, packager_v3->profiles);
898   while (g_hash_table_iter_next (&iter, NULL, &value))
899     {
900       profile = modulemd_profile_copy (MODULEMD_PROFILE (value));
901       modulemd_profile_unset_default (profile);
902       modulemd_module_stream_v2_add_profile (stream_v2, profile);
903       g_clear_object (&profile);
904     }
905 
906   modulemd_module_stream_v2_replace_rpm_api (stream_v2, packager_v3->rpm_api);
907 
908   modulemd_module_stream_v2_replace_rpm_filters (stream_v2,
909                                                  packager_v3->rpm_filters);
910 
911   modulemd_module_stream_v2_replace_demodularized_rpms (
912     stream_v2, packager_v3->demodularized_rpms);
913 
914   COPY_HASHTABLE_BY_VALUE_ADDER (stream_v2,
915                                  packager_v3,
916                                  rpm_components,
917                                  modulemd_module_stream_v2_add_component);
918 
919   COPY_HASHTABLE_BY_VALUE_ADDER (stream_v2,
920                                  packager_v3,
921                                  module_components,
922                                  modulemd_module_stream_v2_add_component);
923 }
924 
925 static void
copy_packager_v3_buildconfig_to_stream_v2(ModulemdModuleStreamV2 * stream_v2,ModulemdBuildConfig * bc)926 copy_packager_v3_buildconfig_to_stream_v2 (ModulemdModuleStreamV2 *stream_v2,
927                                            ModulemdBuildConfig *bc)
928 {
929   g_autoptr (ModulemdDependencies) deps = NULL;
930   g_auto (GStrv) modules = NULL;
931 
932   modulemd_module_stream_v2_set_buildopts (
933     stream_v2, modulemd_build_config_get_buildopts (bc));
934 
935   deps = modulemd_dependencies_new ();
936 
937   modulemd_dependencies_add_buildtime_stream (
938     deps, "platform", modulemd_build_config_get_platform (bc));
939   modulemd_dependencies_add_runtime_stream (
940     deps, "platform", modulemd_build_config_get_platform (bc));
941 
942   modules = modulemd_build_config_get_buildtime_modules_as_strv (bc);
943   for (guint j = 0; j < g_strv_length (modules); j++)
944     {
945       modulemd_dependencies_add_buildtime_stream (
946         deps,
947         modules[j],
948         modulemd_build_config_get_buildtime_requirement_stream (bc,
949                                                                 modules[j]));
950     }
951   g_clear_pointer (&modules, g_strfreev);
952 
953   modules = modulemd_build_config_get_runtime_modules_as_strv (bc);
954   for (guint j = 0; j < g_strv_length (modules); j++)
955     {
956       modulemd_dependencies_add_runtime_stream (
957         deps,
958         modules[j],
959         modulemd_build_config_get_runtime_requirement_stream (bc, modules[j]));
960     }
961   g_clear_pointer (&modules, g_strfreev);
962 
963   modulemd_module_stream_v2_add_dependencies (stream_v2, deps);
964   g_clear_object (&deps);
965 }
966 
967 
968 ModulemdModuleStreamV2 *
modulemd_packager_v3_to_stream_v2(ModulemdPackagerV3 * self,GError ** error)969 modulemd_packager_v3_to_stream_v2 (ModulemdPackagerV3 *self, GError **error)
970 {
971   g_autoptr (ModulemdModuleStreamV2) v2_stream = NULL;
972   g_auto (GStrv) contexts = NULL;
973   g_autoptr (GError) nested_error = NULL;
974   ModulemdBuildopts *buildopts = NULL;
975   ModulemdBuildConfig *bc;
976 
977   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
978   g_return_val_if_fail (MODULEMD_IS_PACKAGER_V3 (self), NULL);
979 
980   v2_stream = modulemd_module_stream_v2_new (
981     modulemd_packager_v3_get_module_name (self),
982     modulemd_packager_v3_get_stream_name (self));
983 
984   /* set attributes that are the same for all streams */
985   copy_packager_v3_common_to_stream_v2 (v2_stream, self);
986 
987   /* get the list of packager build configuration contexts */
988   contexts = modulemd_packager_v3_get_build_config_contexts_as_strv (self);
989 
990   /* If there is exactly one build configuration, use it for the stream */
991   /* context. Otherwise, leave the stream context unset. */
992   if (g_strv_length (contexts) == 1)
993     {
994       modulemd_module_stream_set_context (MODULEMD_MODULE_STREAM (v2_stream),
995                                           contexts[0]);
996     }
997 
998   /* map each BuildConfig object to a Dependencies object within the same StreamV2 object */
999   for (guint i = 0; i < g_strv_length (contexts); i++)
1000     {
1001       bc = modulemd_packager_v3_get_build_config (self, contexts[i]);
1002 
1003       if (i == 0)
1004         {
1005           /* Save the buildopts from the first build configuration to */
1006           /* set the stream buildopts. */
1007           buildopts = modulemd_build_config_get_buildopts (bc);
1008         }
1009 
1010       /* set attributes that are unique per build configuration */
1011       copy_packager_v3_buildconfig_to_stream_v2 (v2_stream, bc);
1012     }
1013   g_clear_pointer (&contexts, g_strfreev);
1014 
1015   /* set the saved buildopts from the first build configuration */
1016   modulemd_module_stream_v2_set_buildopts (v2_stream, buildopts);
1017 
1018   if (!modulemd_module_stream_validate (MODULEMD_MODULE_STREAM (v2_stream),
1019                                         &nested_error))
1020     {
1021       g_propagate_error (error, g_steal_pointer (&nested_error));
1022       return NULL;
1023     }
1024 
1025   return g_steal_pointer (&v2_stream);
1026 }
1027 
1028 ModulemdModuleIndex *
modulemd_packager_v3_to_stream_v2_ext(ModulemdPackagerV3 * self,GError ** error)1029 modulemd_packager_v3_to_stream_v2_ext (ModulemdPackagerV3 *self,
1030                                        GError **error)
1031 {
1032   g_autoptr (ModulemdModuleIndex) index = NULL;
1033   g_autoptr (ModulemdModuleStreamV2) v2_stream = NULL;
1034   g_autoptr (ModulemdDefaults) defaults = NULL;
1035   g_autoptr (GError) nested_error = NULL;
1036 
1037   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1038   g_return_val_if_fail (MODULEMD_IS_PACKAGER_V3 (self), NULL);
1039 
1040   v2_stream = modulemd_packager_v3_to_stream_v2 (self, &nested_error);
1041   if (!v2_stream)
1042     {
1043       g_propagate_error (error, g_steal_pointer (&nested_error));
1044       return NULL;
1045     }
1046 
1047   /* autogen module/stream names if necessary for adding to index */
1048 
1049   modulemd_module_stream_set_autogen_module_name (
1050     MODULEMD_MODULE_STREAM (v2_stream), 0);
1051   modulemd_module_stream_set_autogen_stream_name (
1052     MODULEMD_MODULE_STREAM (v2_stream), 0);
1053 
1054   index = modulemd_module_index_new ();
1055   if (!modulemd_module_index_add_module_stream (
1056         index, MODULEMD_MODULE_STREAM (v2_stream), &nested_error))
1057     {
1058       g_propagate_error (error, g_steal_pointer (&nested_error));
1059       return NULL;
1060     }
1061 
1062   g_clear_object (&v2_stream);
1063 
1064   if (!modulemd_packager_v3_to_defaults (self, &defaults, &nested_error))
1065     {
1066       g_propagate_error (error, g_steal_pointer (&nested_error));
1067       return NULL;
1068     }
1069 
1070   if (defaults)
1071     {
1072       if (!modulemd_module_index_add_defaults (index, defaults, &nested_error))
1073         {
1074           g_propagate_error (error, g_steal_pointer (&nested_error));
1075           return NULL;
1076         }
1077 
1078       g_clear_object (&defaults);
1079     }
1080 
1081   return g_steal_pointer (&index);
1082 }
1083 
1084 
1085 ModulemdModuleIndex *
modulemd_packager_v3_convert_to_index(ModulemdPackagerV3 * self,GError ** error)1086 modulemd_packager_v3_convert_to_index (ModulemdPackagerV3 *self,
1087                                        GError **error)
1088 {
1089   g_auto (GStrv) contexts = NULL;
1090   g_autoptr (ModulemdModuleIndex) index = NULL;
1091   g_autoptr (ModulemdModuleStreamV2) v2_stream = NULL;
1092   g_autoptr (ModulemdDefaults) defaults = NULL;
1093   g_autoptr (GError) nested_error = NULL;
1094   ModulemdBuildConfig *bc;
1095 
1096   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1097   g_return_val_if_fail (MODULEMD_IS_PACKAGER_V3 (self), NULL);
1098 
1099   /* get the list of packager build configuration contexts */
1100   contexts = modulemd_packager_v3_get_build_config_contexts_as_strv (self);
1101 
1102   if (g_strv_length (contexts) == 0)
1103     {
1104       g_set_error_literal (error,
1105                            MODULEMD_ERROR,
1106                            MMD_ERROR_VALIDATE,
1107                            "Packager document with no build configurations "
1108                            "cannot be converted to stream");
1109       return NULL;
1110     }
1111 
1112   /* create a ModuleIndex to contain the results */
1113   index = modulemd_module_index_new ();
1114 
1115   /* create a StreamV2 object for each BuildConfig object */
1116   for (guint i = 0; i < g_strv_length (contexts); i++)
1117     {
1118       bc = modulemd_packager_v3_get_build_config (self, contexts[i]);
1119 
1120       v2_stream = modulemd_module_stream_v2_new (
1121         modulemd_packager_v3_get_module_name (self),
1122         modulemd_packager_v3_get_stream_name (self));
1123 
1124       modulemd_module_stream_set_context (MODULEMD_MODULE_STREAM (v2_stream),
1125                                           contexts[i]);
1126 
1127       /* set attributes that are the same for all streams */
1128       copy_packager_v3_common_to_stream_v2 (v2_stream, self);
1129 
1130       /* set attributes that are unique per build configuration */
1131       copy_packager_v3_buildconfig_to_stream_v2 (v2_stream, bc);
1132 
1133       if (!modulemd_module_stream_validate (MODULEMD_MODULE_STREAM (v2_stream),
1134                                             &nested_error))
1135         {
1136           g_propagate_error (error, g_steal_pointer (&nested_error));
1137           return NULL;
1138         }
1139 
1140       /* autogen module/stream names if necessary for adding to index */
1141 
1142       modulemd_module_stream_set_autogen_module_name (
1143         MODULEMD_MODULE_STREAM (v2_stream), 0);
1144       modulemd_module_stream_set_autogen_stream_name (
1145         MODULEMD_MODULE_STREAM (v2_stream), 0);
1146 
1147       if (!modulemd_module_index_add_module_stream (
1148             index, MODULEMD_MODULE_STREAM (v2_stream), &nested_error))
1149         {
1150           g_propagate_error (error, g_steal_pointer (&nested_error));
1151           return NULL;
1152         }
1153 
1154       g_clear_object (&v2_stream);
1155     }
1156   g_clear_pointer (&contexts, g_strfreev);
1157 
1158   if (!modulemd_packager_v3_to_defaults (self, &defaults, &nested_error))
1159     {
1160       g_propagate_error (error, g_steal_pointer (&nested_error));
1161       return NULL;
1162     }
1163 
1164   if (defaults)
1165     {
1166       if (!modulemd_module_index_add_defaults (index, defaults, &nested_error))
1167         {
1168           g_propagate_error (error, g_steal_pointer (&nested_error));
1169           return NULL;
1170         }
1171 
1172       g_clear_object (&defaults);
1173     }
1174 
1175   return g_steal_pointer (&index);
1176 }
1177 
1178 
1179 static gboolean
1180 modulemd_packager_v3_parse_build_configs (yaml_parser_t *parser,
1181                                           ModulemdPackagerV3 *packager,
1182                                           gboolean strict,
1183                                           GError **error);
1184 
1185 static gboolean
1186 modulemd_packager_v3_parse_refs (yaml_parser_t *parser,
1187                                  ModulemdPackagerV3 *packager,
1188                                  gboolean strict,
1189                                  GError **error);
1190 
1191 static gboolean
1192 modulemd_packager_v3_parse_profiles (yaml_parser_t *parser,
1193                                      ModulemdPackagerV3 *packager,
1194                                      gboolean strict,
1195                                      GError **error);
1196 
1197 static gboolean
1198 modulemd_packager_v3_parse_components (yaml_parser_t *parser,
1199                                        ModulemdPackagerV3 *packager,
1200                                        gboolean strict,
1201                                        GError **error);
1202 
1203 
1204 ModulemdPackagerV3 *
modulemd_packager_v3_parse_yaml(ModulemdSubdocumentInfo * subdoc,GError ** error)1205 modulemd_packager_v3_parse_yaml (ModulemdSubdocumentInfo *subdoc,
1206                                  GError **error)
1207 {
1208   MODULEMD_INIT_TRACE ();
1209   MMD_INIT_YAML_PARSER (parser);
1210   MMD_INIT_YAML_EVENT (event);
1211   gboolean done = FALSE;
1212   const gboolean strict = TRUE; /* PackagerV3 should always parse strictly */
1213   g_autoptr (GError) nested_error = NULL;
1214   g_autoptr (ModulemdPackagerV3) packager = NULL;
1215   g_autoptr (GHashTable) set = NULL;
1216   g_autoptr (GVariant) xmd = NULL;
1217 
1218   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1219 
1220   if (!modulemd_subdocument_info_get_data_parser (
1221         subdoc, &parser, strict, error))
1222     {
1223       return FALSE;
1224     }
1225 
1226   packager = modulemd_packager_v3_new ();
1227 
1228   /* Read the MAPPING_START */
1229   YAML_PARSER_PARSE_WITH_EXIT (&parser, &event, error);
1230   if (event.type != YAML_MAPPING_START_EVENT)
1231     {
1232       MMD_YAML_ERROR_EVENT_EXIT (
1233         error, event, "Data section did not begin with a map.");
1234     }
1235 
1236   /* Process through the mapping */
1237   while (!done)
1238     {
1239       YAML_PARSER_PARSE_WITH_EXIT (&parser, &event, error);
1240 
1241       switch (event.type)
1242         {
1243         case YAML_MAPPING_END_EVENT: done = TRUE; break;
1244 
1245         case YAML_SCALAR_EVENT:
1246           /* Mapping Keys */
1247           if (g_str_equal ((const gchar *)event.data.scalar.value, "name"))
1248             {
1249               MMD_SET_PARSED_YAML_STRING (&parser,
1250                                           error,
1251                                           modulemd_packager_v3_set_module_name,
1252                                           packager);
1253             }
1254 
1255           else if (g_str_equal ((const gchar *)event.data.scalar.value,
1256                                 "stream"))
1257             {
1258               MMD_SET_PARSED_YAML_STRING (&parser,
1259                                           error,
1260                                           modulemd_packager_v3_set_stream_name,
1261                                           packager);
1262             }
1263 
1264           else if (g_str_equal ((const gchar *)event.data.scalar.value,
1265                                 "summary"))
1266             {
1267               MMD_SET_PARSED_YAML_STRING (
1268                 &parser, error, modulemd_packager_v3_set_summary, packager);
1269             }
1270 
1271           else if (g_str_equal ((const gchar *)event.data.scalar.value,
1272                                 "description"))
1273             {
1274               MMD_SET_PARSED_YAML_STRING (&parser,
1275                                           error,
1276                                           modulemd_packager_v3_set_description,
1277                                           packager);
1278             }
1279 
1280           else if (g_str_equal ((const gchar *)event.data.scalar.value,
1281                                 "license"))
1282             {
1283               set = modulemd_yaml_parse_string_set (&parser, &nested_error);
1284               MODULEMD_REPLACE_SET (packager->module_licenses, set);
1285               g_clear_pointer (&set, g_hash_table_unref);
1286             }
1287 
1288           else if (g_str_equal ((const gchar *)event.data.scalar.value, "xmd"))
1289             {
1290               xmd = mmd_parse_xmd (&parser, &nested_error);
1291               if (!xmd)
1292                 {
1293                   g_propagate_error (error, g_steal_pointer (&nested_error));
1294                   return NULL;
1295                 }
1296               modulemd_packager_v3_set_xmd (packager, xmd);
1297               g_clear_pointer (&xmd, g_variant_unref);
1298             }
1299 
1300           else if (g_str_equal ((const gchar *)event.data.scalar.value,
1301                                 "configurations"))
1302             {
1303               if (!modulemd_packager_v3_parse_build_configs (
1304                     &parser, packager, strict, &nested_error))
1305                 {
1306                   g_propagate_error (error, g_steal_pointer (&nested_error));
1307                   return NULL;
1308                 }
1309             }
1310 
1311           else if (g_str_equal ((const gchar *)event.data.scalar.value,
1312                                 "references"))
1313             {
1314               if (!modulemd_packager_v3_parse_refs (
1315                     &parser, packager, strict, &nested_error))
1316                 {
1317                   g_propagate_error (error, g_steal_pointer (&nested_error));
1318                   return NULL;
1319                 }
1320             }
1321 
1322           else if (g_str_equal ((const gchar *)event.data.scalar.value,
1323                                 "profiles"))
1324             {
1325               if (!modulemd_packager_v3_parse_profiles (
1326                     &parser, packager, strict, &nested_error))
1327                 {
1328                   g_propagate_error (error, g_steal_pointer (&nested_error));
1329                   return NULL;
1330                 }
1331             }
1332 
1333           else if (g_str_equal ((const gchar *)event.data.scalar.value, "api"))
1334             {
1335               set = modulemd_yaml_parse_string_set_from_map (
1336                 &parser, "rpms", strict, &nested_error);
1337               modulemd_packager_v3_replace_rpm_api (packager, set);
1338               g_clear_pointer (&set, g_hash_table_unref);
1339             }
1340 
1341           else if (g_str_equal ((const gchar *)event.data.scalar.value,
1342                                 "filter"))
1343             {
1344               set = modulemd_yaml_parse_string_set_from_map (
1345                 &parser, "rpms", strict, &nested_error);
1346               modulemd_packager_v3_replace_rpm_filters (packager, set);
1347               g_clear_pointer (&set, g_hash_table_unref);
1348             }
1349 
1350           else if (g_str_equal ((const gchar *)event.data.scalar.value,
1351                                 "demodularized"))
1352             {
1353               set = modulemd_yaml_parse_string_set_from_map (
1354                 &parser, "rpms", strict, &nested_error);
1355               modulemd_packager_v3_replace_demodularized_rpms (packager, set);
1356               g_clear_pointer (&set, g_hash_table_unref);
1357             }
1358 
1359           else if (g_str_equal ((const gchar *)event.data.scalar.value,
1360                                 "components"))
1361             {
1362               if (!modulemd_packager_v3_parse_components (
1363                     &parser, packager, strict, &nested_error))
1364                 {
1365                   g_propagate_error (error, g_steal_pointer (&nested_error));
1366                   return NULL;
1367                 }
1368             }
1369 
1370           else
1371             {
1372               SKIP_UNKNOWN (&parser,
1373                             NULL,
1374                             "Unexpected key in packager v3 document: %s",
1375                             (const gchar *)event.data.scalar.value);
1376               break;
1377             }
1378 
1379           break;
1380 
1381         default:
1382           MMD_YAML_ERROR_EVENT_EXIT (
1383             error,
1384             event,
1385             "Unexpected YAML event in ModuleStreamV2: %s",
1386             mmd_yaml_get_event_name (event.type));
1387           break;
1388         }
1389       yaml_event_delete (&event);
1390     }
1391 
1392   return g_steal_pointer (&packager);
1393 }
1394 
1395 
1396 static gboolean
modulemd_packager_v3_parse_build_configs(yaml_parser_t * parser,ModulemdPackagerV3 * packager,gboolean strict,GError ** error)1397 modulemd_packager_v3_parse_build_configs (yaml_parser_t *parser,
1398                                           ModulemdPackagerV3 *packager,
1399                                           gboolean strict,
1400                                           GError **error)
1401 {
1402   MMD_INIT_YAML_EVENT (event);
1403   gboolean done = FALSE;
1404   g_autoptr (ModulemdBuildConfig) buildconfig = NULL;
1405   g_autoptr (GError) nested_error = NULL;
1406 
1407   YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
1408   if (event.type != YAML_SEQUENCE_START_EVENT)
1409     {
1410       MMD_YAML_ERROR_EVENT_EXIT_BOOL (
1411         error, event, "Unexpected YAML event in build_configs");
1412     }
1413 
1414   while (!done)
1415     {
1416       YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
1417 
1418       switch (event.type)
1419         {
1420         case YAML_SEQUENCE_END_EVENT: done = TRUE; break;
1421 
1422         case YAML_MAPPING_START_EVENT:
1423           buildconfig =
1424             modulemd_build_config_parse_yaml (parser, strict, &nested_error);
1425           if (!buildconfig)
1426             {
1427               g_propagate_error (error, g_steal_pointer (&nested_error));
1428               return FALSE;
1429             }
1430           modulemd_packager_v3_add_build_config (packager, buildconfig);
1431           g_clear_object (&buildconfig);
1432           break;
1433 
1434         default:
1435           MMD_YAML_ERROR_EVENT_EXIT_BOOL (
1436             error, event, "Unexpected YAML event in build_config list");
1437           break;
1438         }
1439       yaml_event_delete (&event);
1440     }
1441 
1442   return TRUE;
1443 }
1444 
1445 
1446 static gboolean
modulemd_packager_v3_parse_refs(yaml_parser_t * parser,ModulemdPackagerV3 * packager,gboolean strict,GError ** error)1447 modulemd_packager_v3_parse_refs (yaml_parser_t *parser,
1448                                  ModulemdPackagerV3 *packager,
1449                                  gboolean strict,
1450                                  GError **error)
1451 {
1452   MODULEMD_INIT_TRACE ();
1453   MMD_INIT_YAML_EVENT (event);
1454   gboolean done = FALSE;
1455   g_autofree gchar *scalar = NULL;
1456   g_autoptr (GError) nested_error = NULL;
1457 
1458   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1459 
1460   /* Process through the map */
1461   /* We *must* get a MAPPING_START here */
1462   YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
1463   if (event.type != YAML_MAPPING_START_EVENT)
1464     {
1465       MMD_YAML_ERROR_EVENT_EXIT_BOOL (
1466         error,
1467         event,
1468         "Got %s instead of MAPPING_START in references.",
1469         mmd_yaml_get_event_name (event.type));
1470     }
1471 
1472   while (!done)
1473     {
1474       YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
1475 
1476       switch (event.type)
1477         {
1478         case YAML_MAPPING_END_EVENT: done = TRUE; break;
1479 
1480         case YAML_SCALAR_EVENT:
1481           if (g_str_equal ((const gchar *)event.data.scalar.value,
1482                            "community"))
1483             {
1484               scalar = modulemd_yaml_parse_string (parser, &nested_error);
1485               if (!scalar)
1486                 {
1487                   g_propagate_error (error, g_steal_pointer (&nested_error));
1488                   return FALSE;
1489                 }
1490 
1491               modulemd_packager_v3_set_community (packager, scalar);
1492               g_clear_pointer (&scalar, g_free);
1493             }
1494 
1495           else if (g_str_equal ((const gchar *)event.data.scalar.value,
1496                                 "documentation"))
1497             {
1498               scalar = modulemd_yaml_parse_string (parser, &nested_error);
1499               if (!scalar)
1500                 {
1501                   g_propagate_error (error, g_steal_pointer (&nested_error));
1502                   return FALSE;
1503                 }
1504 
1505               modulemd_packager_v3_set_documentation (packager, scalar);
1506               g_clear_pointer (&scalar, g_free);
1507             }
1508 
1509           else if (g_str_equal ((const gchar *)event.data.scalar.value,
1510                                 "tracker"))
1511             {
1512               scalar = modulemd_yaml_parse_string (parser, &nested_error);
1513               if (!scalar)
1514                 {
1515                   g_propagate_error (error, g_steal_pointer (&nested_error));
1516                   return FALSE;
1517                 }
1518 
1519               modulemd_packager_v3_set_tracker (packager, scalar);
1520               g_clear_pointer (&scalar, g_free);
1521             }
1522 
1523           else
1524             {
1525               SKIP_UNKNOWN (parser,
1526                             FALSE,
1527                             "Unexpected key in references: %s",
1528                             (const gchar *)event.data.scalar.value);
1529               break;
1530             }
1531           break;
1532 
1533         default:
1534           MMD_YAML_ERROR_EVENT_EXIT_BOOL (
1535             error,
1536             event,
1537             "Unexpected YAML event in references: %s",
1538             mmd_yaml_get_event_name (event.type));
1539           break;
1540         }
1541       yaml_event_delete (&event);
1542     }
1543 
1544   return TRUE;
1545 }
1546 
1547 
1548 static gboolean
modulemd_packager_v3_parse_profiles(yaml_parser_t * parser,ModulemdPackagerV3 * packager,gboolean strict,GError ** error)1549 modulemd_packager_v3_parse_profiles (yaml_parser_t *parser,
1550                                      ModulemdPackagerV3 *packager,
1551                                      gboolean strict,
1552                                      GError **error)
1553 {
1554   MODULEMD_INIT_TRACE ();
1555   MMD_INIT_YAML_EVENT (event);
1556   gboolean done = FALSE;
1557   g_autoptr (GError) nested_error = NULL;
1558   g_autoptr (ModulemdProfile) profile = NULL;
1559 
1560   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1561 
1562   /* Process through the map */
1563   /* We *must* get a MAPPING_START here */
1564   YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
1565   if (event.type != YAML_MAPPING_START_EVENT)
1566     {
1567       MMD_YAML_ERROR_EVENT_EXIT_BOOL (
1568         error,
1569         event,
1570         "Got %s instead of MAPPING_START in profiles.",
1571         mmd_yaml_get_event_name (event.type));
1572     }
1573 
1574   while (!done)
1575     {
1576       YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
1577 
1578       switch (event.type)
1579         {
1580         case YAML_MAPPING_END_EVENT: done = TRUE; break;
1581 
1582         case YAML_SCALAR_EVENT:
1583           profile = modulemd_profile_parse_yaml (
1584             parser,
1585             (const gchar *)event.data.scalar.value,
1586             strict,
1587             &nested_error);
1588           if (!profile)
1589             {
1590               g_propagate_error (error, g_steal_pointer (&nested_error));
1591               return FALSE;
1592             }
1593 
1594           modulemd_packager_v3_add_profile (packager, profile);
1595           g_clear_pointer (&profile, g_object_unref);
1596           break;
1597 
1598         default:
1599           MMD_YAML_ERROR_EVENT_EXIT_BOOL (
1600             error,
1601             event,
1602             "Unexpected YAML event in profiles: %s",
1603             mmd_yaml_get_event_name (event.type));
1604           break;
1605         }
1606       yaml_event_delete (&event);
1607     }
1608 
1609   return TRUE;
1610 }
1611 
1612 
1613 static gboolean
1614 modulemd_packager_v3_parse_rpm_components (yaml_parser_t *parser,
1615                                            ModulemdPackagerV3 *packager,
1616                                            gboolean strict,
1617                                            GError **error);
1618 static gboolean
1619 modulemd_packager_v3_parse_module_components (yaml_parser_t *parser,
1620                                               ModulemdPackagerV3 *packager,
1621                                               gboolean strict,
1622                                               GError **error);
1623 
1624 
1625 static gboolean
modulemd_packager_v3_parse_components(yaml_parser_t * parser,ModulemdPackagerV3 * packager,gboolean strict,GError ** error)1626 modulemd_packager_v3_parse_components (yaml_parser_t *parser,
1627                                        ModulemdPackagerV3 *packager,
1628                                        gboolean strict,
1629                                        GError **error)
1630 {
1631   MODULEMD_INIT_TRACE ();
1632   MMD_INIT_YAML_EVENT (event);
1633   gboolean done = FALSE;
1634   g_autoptr (GError) nested_error = NULL;
1635 
1636   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1637 
1638   /* Process through the sequence */
1639   /* We *must* get a MAPPING_START here */
1640   YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
1641   if (event.type != YAML_MAPPING_START_EVENT)
1642     {
1643       MMD_YAML_ERROR_EVENT_EXIT_BOOL (
1644         error,
1645         event,
1646         "Got %s instead of MAPPING_START in components.",
1647         mmd_yaml_get_event_name (event.type));
1648     }
1649 
1650   while (!done)
1651     {
1652       YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
1653 
1654       switch (event.type)
1655         {
1656         case YAML_MAPPING_END_EVENT: done = TRUE; break;
1657 
1658         case YAML_SCALAR_EVENT:
1659           if (g_str_equal ((const gchar *)event.data.scalar.value, "rpms"))
1660             {
1661               if (!modulemd_packager_v3_parse_rpm_components (
1662                     parser, packager, strict, &nested_error))
1663                 {
1664                   g_propagate_error (error, g_steal_pointer (&nested_error));
1665                   return FALSE;
1666                 }
1667             }
1668 
1669           else if (g_str_equal ((const gchar *)event.data.scalar.value,
1670                                 "modules"))
1671             {
1672               if (!modulemd_packager_v3_parse_module_components (
1673                     parser, packager, strict, &nested_error))
1674                 {
1675                   g_propagate_error (error, g_steal_pointer (&nested_error));
1676                   return FALSE;
1677                 }
1678             }
1679 
1680           else
1681             {
1682               SKIP_UNKNOWN (parser,
1683                             FALSE,
1684                             "Unexpected key in components: %s",
1685                             (const gchar *)event.data.scalar.value);
1686             }
1687 
1688           break;
1689 
1690 
1691         default:
1692           MMD_YAML_ERROR_EVENT_EXIT_BOOL (
1693             error,
1694             event,
1695             "Unexpected YAML event in components: %s",
1696             mmd_yaml_get_event_name (event.type));
1697           break;
1698         }
1699       yaml_event_delete (&event);
1700     }
1701 
1702   return TRUE;
1703 }
1704 
1705 
1706 static gboolean
modulemd_packager_v3_parse_rpm_components(yaml_parser_t * parser,ModulemdPackagerV3 * packager,gboolean strict,GError ** error)1707 modulemd_packager_v3_parse_rpm_components (yaml_parser_t *parser,
1708                                            ModulemdPackagerV3 *packager,
1709                                            gboolean strict,
1710                                            GError **error)
1711 {
1712   MODULEMD_INIT_TRACE ();
1713   MMD_INIT_YAML_EVENT (event);
1714   gboolean done = FALSE;
1715   g_autoptr (GError) nested_error = NULL;
1716   g_autoptr (ModulemdComponentRpm) component = NULL;
1717 
1718   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1719 
1720   /* We *must* get a MAPPING_START here */
1721   YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
1722   if (event.type != YAML_MAPPING_START_EVENT)
1723     {
1724       MMD_YAML_ERROR_EVENT_EXIT_BOOL (
1725         error,
1726         event,
1727         "Got %s instead of MAPPING_START in rpm components.",
1728         mmd_yaml_get_event_name (event.type));
1729     }
1730 
1731   while (!done)
1732     {
1733       YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
1734 
1735       switch (event.type)
1736         {
1737         case YAML_MAPPING_END_EVENT: done = TRUE; break;
1738 
1739         case YAML_SCALAR_EVENT:
1740           component = modulemd_component_rpm_parse_yaml (
1741             parser,
1742             (const gchar *)event.data.scalar.value,
1743             strict,
1744             &nested_error);
1745           if (!component)
1746             {
1747               g_propagate_error (error, g_steal_pointer (&nested_error));
1748               return FALSE;
1749             }
1750           modulemd_packager_v3_add_component (packager,
1751                                               (ModulemdComponent *)component);
1752           g_clear_pointer (&component, g_object_unref);
1753           break;
1754 
1755         default:
1756           MMD_YAML_ERROR_EVENT_EXIT_BOOL (
1757             error,
1758             event,
1759             "Unexpected YAML event in RPM component: %s",
1760             mmd_yaml_get_event_name (event.type));
1761           break;
1762         }
1763       yaml_event_delete (&event);
1764     }
1765 
1766   return TRUE;
1767 }
1768 
1769 
1770 static gboolean
modulemd_packager_v3_parse_module_components(yaml_parser_t * parser,ModulemdPackagerV3 * packager,gboolean strict,GError ** error)1771 modulemd_packager_v3_parse_module_components (yaml_parser_t *parser,
1772                                               ModulemdPackagerV3 *packager,
1773                                               gboolean strict,
1774                                               GError **error)
1775 {
1776   MODULEMD_INIT_TRACE ();
1777   MMD_INIT_YAML_EVENT (event);
1778   gboolean done = FALSE;
1779   g_autoptr (GError) nested_error = NULL;
1780   g_autoptr (ModulemdComponentModule) component = NULL;
1781 
1782   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1783 
1784   /* We *must* get a MAPPING_START here */
1785   YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
1786   if (event.type != YAML_MAPPING_START_EVENT)
1787     {
1788       MMD_YAML_ERROR_EVENT_EXIT_BOOL (
1789         error,
1790         event,
1791         "Got %s instead of MAPPING_START in module components.",
1792         mmd_yaml_get_event_name (event.type));
1793     }
1794 
1795   while (!done)
1796     {
1797       YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
1798 
1799       switch (event.type)
1800         {
1801         case YAML_MAPPING_END_EVENT: done = TRUE; break;
1802 
1803         case YAML_SCALAR_EVENT:
1804           component = modulemd_component_module_parse_yaml (
1805             parser,
1806             (const gchar *)event.data.scalar.value,
1807             strict,
1808             &nested_error);
1809           if (!component)
1810             {
1811               g_propagate_error (error, g_steal_pointer (&nested_error));
1812               return FALSE;
1813             }
1814           modulemd_packager_v3_add_component (packager,
1815                                               (ModulemdComponent *)component);
1816           g_clear_pointer (&component, g_object_unref);
1817           break;
1818 
1819         default:
1820           MMD_YAML_ERROR_EVENT_EXIT_BOOL (
1821             error,
1822             event,
1823             "Unexpected YAML event in module component: %s",
1824             mmd_yaml_get_event_name (event.type));
1825           break;
1826         }
1827       yaml_event_delete (&event);
1828     }
1829 
1830   return TRUE;
1831 }
1832 
1833 
1834 gboolean
modulemd_packager_v3_emit_yaml(ModulemdPackagerV3 * self,yaml_emitter_t * emitter,GError ** error)1835 modulemd_packager_v3_emit_yaml (ModulemdPackagerV3 *self,
1836                                 yaml_emitter_t *emitter,
1837                                 GError **error)
1838 {
1839   MODULEMD_INIT_TRACE ();
1840   g_autoptr (GError) nested_error = NULL;
1841   gsize i;
1842   g_autoptr (GPtrArray) keys = NULL;
1843   gboolean ret;
1844 
1845   /* Emit document headers */
1846   if (!modulemd_yaml_emit_document_headers (
1847         emitter, MODULEMD_YAML_DOC_PACKAGER, MD_PACKAGER_VERSION_THREE, error))
1848     {
1849       return FALSE;
1850     }
1851 
1852   /* Start data: */
1853   EMIT_MAPPING_START (emitter, error);
1854 
1855   if (modulemd_packager_v3_get_module_name (self) != NULL)
1856     {
1857       EMIT_KEY_VALUE (
1858         emitter, error, "name", modulemd_packager_v3_get_module_name (self));
1859     }
1860 
1861   if (modulemd_packager_v3_get_stream_name (self) != NULL)
1862     {
1863       EMIT_KEY_VALUE_FULL (emitter,
1864                            error,
1865                            "stream",
1866                            modulemd_packager_v3_get_stream_name (self),
1867                            YAML_DOUBLE_QUOTED_SCALAR_STYLE);
1868     }
1869 
1870   EMIT_KEY_VALUE (
1871     emitter, error, "summary", modulemd_packager_v3_get_summary (self));
1872   EMIT_KEY_VALUE_FULL (emitter,
1873                        error,
1874                        "description",
1875                        modulemd_packager_v3_get_description (self),
1876                        YAML_FOLDED_SCALAR_STYLE);
1877 
1878   if (NON_EMPTY_TABLE (self->module_licenses))
1879     {
1880       EMIT_STRING_SET (emitter, error, "license", self->module_licenses);
1881     }
1882 
1883   if (self->xmd != NULL)
1884     {
1885       EMIT_SCALAR (emitter, error, "xmd");
1886       if (!modulemd_yaml_emit_variant (emitter, self->xmd, error))
1887         {
1888           return FALSE;
1889         }
1890     }
1891 
1892   if (NON_EMPTY_TABLE (self->build_configs))
1893     {
1894       EMIT_SCALAR (emitter, error, "configurations");
1895       EMIT_SEQUENCE_START (emitter, error);
1896       keys =
1897         modulemd_ordered_str_keys (self->build_configs, modulemd_strcmp_sort);
1898       for (i = 0; i < keys->len; i++)
1899         {
1900           ret = modulemd_build_config_emit_yaml (
1901             g_hash_table_lookup (self->build_configs,
1902                                  g_ptr_array_index (keys, i)),
1903             emitter,
1904             error);
1905           if (!ret)
1906             {
1907               return FALSE;
1908             }
1909         }
1910       EMIT_SEQUENCE_END (emitter, error);
1911     }
1912 
1913 
1914   if (self->community || self->documentation || self->tracker)
1915     {
1916       EMIT_SCALAR (emitter, error, "references");
1917       EMIT_MAPPING_START (emitter, error);
1918       EMIT_KEY_VALUE_IF_SET (emitter, error, "community", self->community);
1919       EMIT_KEY_VALUE_IF_SET (
1920         emitter, error, "documentation", self->documentation);
1921       EMIT_KEY_VALUE_IF_SET (emitter, error, "tracker", self->tracker);
1922       EMIT_MAPPING_END (emitter, error);
1923     }
1924 
1925   EMIT_HASHTABLE_VALUES_IF_NON_EMPTY (
1926     emitter, error, "profiles", self->profiles, modulemd_profile_emit_yaml);
1927 
1928   if (NON_EMPTY_TABLE (self->rpm_api))
1929     {
1930       EMIT_SCALAR (emitter, error, "api");
1931       EMIT_MAPPING_START (emitter, error);
1932       EMIT_STRING_SET (emitter, error, "rpms", self->rpm_api);
1933       EMIT_MAPPING_END (emitter, error);
1934     }
1935 
1936   if (NON_EMPTY_TABLE (self->rpm_filters))
1937     {
1938       EMIT_SCALAR (emitter, error, "filter");
1939       EMIT_MAPPING_START (emitter, error);
1940       EMIT_STRING_SET (emitter, error, "rpms", self->rpm_filters);
1941       EMIT_MAPPING_END (emitter, error);
1942     }
1943 
1944   if (NON_EMPTY_TABLE (self->demodularized_rpms))
1945     {
1946       EMIT_SCALAR (emitter, error, "demodularized");
1947       EMIT_MAPPING_START (emitter, error);
1948       EMIT_STRING_SET (emitter, error, "rpms", self->demodularized_rpms);
1949       EMIT_MAPPING_END (emitter, error);
1950     }
1951 
1952   if (NON_EMPTY_TABLE (self->rpm_components) ||
1953       NON_EMPTY_TABLE (self->module_components))
1954     {
1955       EMIT_SCALAR (emitter, error, "components");
1956       EMIT_MAPPING_START (emitter, error);
1957       EMIT_HASHTABLE_VALUES_IF_NON_EMPTY (emitter,
1958                                           error,
1959                                           "rpms",
1960                                           self->rpm_components,
1961                                           modulemd_component_rpm_emit_yaml);
1962       EMIT_HASHTABLE_VALUES_IF_NON_EMPTY (emitter,
1963                                           error,
1964                                           "modules",
1965                                           self->module_components,
1966                                           modulemd_component_module_emit_yaml);
1967       EMIT_MAPPING_END (emitter, error);
1968     }
1969 
1970   /* The "data" mapping */
1971   EMIT_MAPPING_END (emitter, error);
1972   /* The overall document mapping */
1973   EMIT_MAPPING_END (emitter, error);
1974   if (!mmd_emitter_end_document (emitter, error))
1975     {
1976       return FALSE;
1977     }
1978 
1979   return TRUE;
1980 }
1981