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-component-module.h"
15 #include "private/modulemd-component-module-private.h"
16 #include "private/modulemd-component-private.h"
17 #include "private/modulemd-util.h"
18 #include "private/modulemd-yaml.h"
19 
20 #define CM_DEFAULT_STRING "__UNSET_COMPONENT_MODULE__"
21 
22 struct _ModulemdComponentModule
23 {
24   GObject parent_instance;
25 
26   gchar *ref;
27   gchar *repository;
28 };
29 
30 G_DEFINE_TYPE (ModulemdComponentModule,
31                modulemd_component_module,
32                MODULEMD_TYPE_COMPONENT)
33 
34 enum
35 {
36   PROP_0,
37 
38   PROP_REF,
39   PROP_REPOSITORY,
40 
41   N_PROPS
42 };
43 
44 static GParamSpec *properties[N_PROPS];
45 
46 
47 ModulemdComponentModule *
modulemd_component_module_new(const gchar * key)48 modulemd_component_module_new (const gchar *key)
49 {
50   return g_object_new (MODULEMD_TYPE_COMPONENT_MODULE, "name", key, NULL);
51 }
52 
53 
54 static void
modulemd_component_module_finalize(GObject * object)55 modulemd_component_module_finalize (GObject *object)
56 {
57   ModulemdComponentModule *self = (ModulemdComponentModule *)object;
58 
59   g_clear_pointer (&self->ref, g_free);
60   g_clear_pointer (&self->repository, g_free);
61 
62   G_OBJECT_CLASS (modulemd_component_module_parent_class)->finalize (object);
63 }
64 
65 
66 static gboolean
modulemd_component_module_equals(ModulemdComponent * self_1,ModulemdComponent * self_2)67 modulemd_component_module_equals (ModulemdComponent *self_1,
68                                   ModulemdComponent *self_2)
69 {
70   ModulemdComponentModule *module_self_1 = NULL;
71   ModulemdComponentModule *module_self_2 = NULL;
72 
73   g_return_val_if_fail (MODULEMD_IS_COMPONENT_MODULE (self_1), FALSE);
74   module_self_1 = MODULEMD_COMPONENT_MODULE (self_1);
75   g_return_val_if_fail (MODULEMD_IS_COMPONENT_MODULE (self_2), FALSE);
76   module_self_2 = MODULEMD_COMPONENT_MODULE (self_2);
77 
78   if (!MODULEMD_COMPONENT_CLASS (modulemd_component_module_parent_class)
79          ->equals (self_1, self_2))
80     {
81       return FALSE;
82     }
83 
84   if (g_strcmp0 (module_self_1->ref, module_self_2->ref) != 0)
85     {
86       return FALSE;
87     }
88 
89   if (g_strcmp0 (module_self_1->repository, module_self_2->repository) != 0)
90     {
91       return FALSE;
92     }
93 
94   return TRUE;
95 }
96 
97 
98 static ModulemdComponent *
modulemd_component_module_copy(ModulemdComponent * self,const gchar * key)99 modulemd_component_module_copy (ModulemdComponent *self, const gchar *key)
100 {
101   ModulemdComponentModule *module_self = NULL;
102   g_autoptr (ModulemdComponentModule) copy = NULL;
103   g_return_val_if_fail (MODULEMD_IS_COMPONENT_MODULE (self), NULL);
104   module_self = MODULEMD_COMPONENT_MODULE (self);
105 
106   copy = MODULEMD_COMPONENT_MODULE (
107     MODULEMD_COMPONENT_CLASS (modulemd_component_module_parent_class)
108       ->copy (self, key));
109 
110   modulemd_component_module_set_ref (
111     copy, modulemd_component_module_get_ref (module_self));
112   modulemd_component_module_set_repository (
113     copy, modulemd_component_module_get_repository (module_self));
114 
115   return MODULEMD_COMPONENT (g_steal_pointer (&copy));
116 }
117 
118 
119 void
modulemd_component_module_set_ref(ModulemdComponentModule * self,const gchar * ref)120 modulemd_component_module_set_ref (ModulemdComponentModule *self,
121                                    const gchar *ref)
122 {
123   g_return_if_fail (MODULEMD_IS_COMPONENT_MODULE (self));
124 
125   g_clear_pointer (&self->ref, g_free);
126   self->ref = g_strdup (ref);
127 
128   g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_REF]);
129 }
130 
131 
132 const gchar *
modulemd_component_module_get_ref(ModulemdComponentModule * self)133 modulemd_component_module_get_ref (ModulemdComponentModule *self)
134 {
135   g_return_val_if_fail (MODULEMD_IS_COMPONENT_MODULE (self), NULL);
136 
137   return self->ref;
138 }
139 
140 
141 void
modulemd_component_module_set_repository(ModulemdComponentModule * self,const gchar * repository)142 modulemd_component_module_set_repository (ModulemdComponentModule *self,
143                                           const gchar *repository)
144 {
145   g_return_if_fail (MODULEMD_IS_COMPONENT_MODULE (self));
146 
147   g_clear_pointer (&self->repository, g_free);
148   self->repository = g_strdup (repository);
149 
150   g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_REPOSITORY]);
151 }
152 
153 
154 const gchar *
modulemd_component_module_get_repository(ModulemdComponentModule * self)155 modulemd_component_module_get_repository (ModulemdComponentModule *self)
156 {
157   g_return_val_if_fail (MODULEMD_IS_COMPONENT_MODULE (self), NULL);
158 
159   return self->repository;
160 }
161 
162 
163 static void
modulemd_component_module_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)164 modulemd_component_module_get_property (GObject *object,
165                                         guint prop_id,
166                                         GValue *value,
167                                         GParamSpec *pspec)
168 {
169   ModulemdComponentModule *self = MODULEMD_COMPONENT_MODULE (object);
170 
171   switch (prop_id)
172     {
173     case PROP_REF:
174       g_value_set_string (value, modulemd_component_module_get_ref (self));
175       break;
176     case PROP_REPOSITORY:
177       g_value_set_string (value,
178                           modulemd_component_module_get_repository (self));
179       break;
180     default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
181     }
182 }
183 
184 
185 static void
modulemd_component_module_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)186 modulemd_component_module_set_property (GObject *object,
187                                         guint prop_id,
188                                         const GValue *value,
189                                         GParamSpec *pspec)
190 {
191   ModulemdComponentModule *self = MODULEMD_COMPONENT_MODULE (object);
192 
193   switch (prop_id)
194     {
195     case PROP_REF:
196       modulemd_component_module_set_ref (self, g_value_get_string (value));
197       break;
198     case PROP_REPOSITORY:
199       modulemd_component_module_set_repository (self,
200                                                 g_value_get_string (value));
201       break;
202     default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
203     }
204 }
205 
206 
207 static void
modulemd_component_module_class_init(ModulemdComponentModuleClass * klass)208 modulemd_component_module_class_init (ModulemdComponentModuleClass *klass)
209 {
210   GObjectClass *object_class = G_OBJECT_CLASS (klass);
211   ModulemdComponentClass *component_class =
212     MODULEMD_COMPONENT_CLASS (object_class);
213 
214   object_class->finalize = modulemd_component_module_finalize;
215   object_class->get_property = modulemd_component_module_get_property;
216   object_class->set_property = modulemd_component_module_set_property;
217 
218   component_class->copy = modulemd_component_module_copy;
219   component_class->equals = modulemd_component_module_equals;
220 
221   properties[PROP_REF] =
222     g_param_spec_string ("ref",
223                          "Ref",
224                          "The commit ID in the SCM repository.",
225                          CM_DEFAULT_STRING,
226                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
227   properties[PROP_REPOSITORY] =
228     g_param_spec_string ("repository",
229                          "Repository",
230                          "The URI of the SCM repository.",
231                          CM_DEFAULT_STRING,
232                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
233   g_object_class_install_properties (object_class, N_PROPS, properties);
234 }
235 
236 
237 static void
modulemd_component_module_init(ModulemdComponentModule * self)238 modulemd_component_module_init (ModulemdComponentModule *self)
239 {
240   /* Nothing to init */
241 }
242 
243 
244 gboolean
modulemd_component_module_emit_yaml(ModulemdComponentModule * self,yaml_emitter_t * emitter,GError ** error)245 modulemd_component_module_emit_yaml (ModulemdComponentModule *self,
246                                      yaml_emitter_t *emitter,
247                                      GError **error)
248 {
249   MODULEMD_INIT_TRACE ();
250   MMD_INIT_YAML_EVENT (event);
251 
252   if (!modulemd_component_emit_yaml_start (
253         MODULEMD_COMPONENT (self), emitter, error))
254     {
255       return FALSE;
256     }
257 
258   if (modulemd_component_module_get_repository (self) != NULL)
259     {
260       if (!mmd_emitter_scalar (
261             emitter, "repository", YAML_PLAIN_SCALAR_STYLE, error))
262         {
263           return FALSE;
264         }
265 
266       if (!mmd_emitter_scalar (emitter,
267                                modulemd_component_module_get_repository (self),
268                                YAML_PLAIN_SCALAR_STYLE,
269                                error))
270         {
271           return FALSE;
272         }
273     }
274 
275   if (modulemd_component_module_get_ref (self) != NULL)
276     {
277       if (!mmd_emitter_scalar (emitter, "ref", YAML_PLAIN_SCALAR_STYLE, error))
278         {
279           return FALSE;
280         }
281 
282       if (!mmd_emitter_scalar (emitter,
283                                modulemd_component_module_get_ref (self),
284                                YAML_PLAIN_SCALAR_STYLE,
285                                error))
286         {
287           return FALSE;
288         }
289     }
290 
291   if (!modulemd_component_emit_yaml_build_common (
292         MODULEMD_COMPONENT (self), emitter, error))
293     {
294       return FALSE;
295     }
296 
297   if (!mmd_emitter_end_mapping (emitter, error))
298     {
299       return FALSE;
300     }
301 
302   return TRUE;
303 }
304 
305 
306 ModulemdComponentModule *
modulemd_component_module_parse_yaml(yaml_parser_t * parser,const gchar * name,gboolean strict,GError ** error)307 modulemd_component_module_parse_yaml (yaml_parser_t *parser,
308                                       const gchar *name,
309                                       gboolean strict,
310                                       GError **error)
311 {
312   MODULEMD_INIT_TRACE ();
313   MMD_INIT_YAML_EVENT (event);
314   gboolean done = FALSE;
315   gboolean in_map = FALSE;
316   g_autofree gchar *value = NULL;
317   gint buildorder = 0;
318   g_autoptr (ModulemdComponentModule) m = NULL;
319 
320   g_autoptr (GError) nested_error = NULL;
321 
322   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
323 
324   m = modulemd_component_module_new (name);
325 
326   while (!done)
327     {
328       YAML_PARSER_PARSE_WITH_EXIT (parser, &event, error);
329 
330       switch (event.type)
331         {
332         case YAML_MAPPING_START_EVENT: in_map = TRUE; break;
333 
334         case YAML_MAPPING_END_EVENT:
335           in_map = FALSE;
336           done = TRUE;
337           break;
338 
339         case YAML_SCALAR_EVENT:
340           if (!in_map)
341             {
342               MMD_YAML_ERROR_EVENT_EXIT (
343                 error, event, "Missing mapping in module component entry");
344               break;
345             }
346           if (g_str_equal ((const gchar *)event.data.scalar.value,
347                            "rationale"))
348             {
349               value = modulemd_yaml_parse_string (parser, &nested_error);
350               if (!value)
351                 {
352                   MMD_YAML_ERROR_EVENT_EXIT (
353                     error,
354                     event,
355                     "Failed to parse rationale in component: %s",
356                     nested_error->message);
357                 }
358 
359               modulemd_component_set_rationale (MODULEMD_COMPONENT (m), value);
360               g_clear_pointer (&value, g_free);
361             }
362           else if (g_str_equal ((const gchar *)event.data.scalar.value,
363                                 "repository"))
364             {
365               value = modulemd_yaml_parse_string (parser, &nested_error);
366               if (!value)
367                 {
368                   MMD_YAML_ERROR_EVENT_EXIT (
369                     error,
370                     event,
371                     "Failed to parse repository in component: %s",
372                     nested_error->message);
373                 }
374 
375               modulemd_component_module_set_repository (m, value);
376               g_clear_pointer (&value, g_free);
377             }
378           else if (g_str_equal ((const gchar *)event.data.scalar.value, "ref"))
379             {
380               value = modulemd_yaml_parse_string (parser, &nested_error);
381               if (!value)
382                 {
383                   MMD_YAML_ERROR_EVENT_EXIT (
384                     error,
385                     event,
386                     "Failed to parse ref in component: %s",
387                     nested_error->message);
388                 }
389 
390               modulemd_component_module_set_ref (m, value);
391               g_clear_pointer (&value, g_free);
392             }
393           else if (g_str_equal ((const gchar *)event.data.scalar.value,
394                                 "buildonly"))
395             {
396               if (!modulemd_component_parse_buildonly (
397                     MODULEMD_COMPONENT (m), parser, &nested_error))
398                 {
399                   MMD_YAML_ERROR_EVENT_EXIT (
400                     error,
401                     event,
402                     "Failed to parse buildonly in component: %s",
403                     nested_error->message);
404                 }
405             }
406           else if (g_str_equal ((const gchar *)event.data.scalar.value,
407                                 "buildorder"))
408             {
409               buildorder = modulemd_yaml_parse_int64 (parser, &nested_error);
410               if (buildorder == 0 && nested_error != NULL)
411                 {
412                   MMD_YAML_ERROR_EVENT_EXIT (
413                     error,
414                     event,
415                     "Failed to parse buildorder in component: %s",
416                     nested_error->message);
417                 }
418 
419               modulemd_component_set_buildorder (MODULEMD_COMPONENT (m),
420                                                  buildorder);
421             }
422           else
423             {
424               SKIP_UNKNOWN (parser,
425                             NULL,
426                             "Unexpected key in module component body: %s",
427                             (const gchar *)event.data.scalar.value);
428               break;
429             }
430           break;
431         default:
432           /* We received a YAML event we shouldn't expect at this level */
433           MMD_YAML_ERROR_EVENT_EXIT (
434             error, event, "Unexpected YAML event in module component");
435           break;
436         }
437       yaml_event_delete (&event);
438     }
439 
440   return g_steal_pointer (&m);
441 }
442