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 <glib.h>
15 #include <inttypes.h>
16 #include <yaml.h>
17
18 #include "modulemd-errors.h"
19 #include "modulemd-obsoletes.h"
20 #include "private/modulemd-obsoletes-private.h"
21 #include "private/modulemd-util.h"
22
23 #include "private/modulemd-subdocument-info-private.h"
24 #include "private/modulemd-util.h"
25 #include "private/modulemd-yaml.h"
26
27 #define O_DEFAULT_STRING "__obsoletes_VALUE_UNSET__"
28 #define O_PLACEHOLDER_STRING "__obsoletes_VALUE_NOT_YET_SET__"
29
30 struct _ModulemdObsoletes
31 {
32 GObject parent_instance;
33
34 guint64 mdversion;
35 guint64 modified;
36 gboolean reset;
37 gchar *module_name;
38 gchar *module_stream;
39 gchar *module_context;
40 guint64 eol_date;
41 gchar *message;
42
43 /* Stream is obsoleted by exactly one other stream */
44 gchar *obsoleted_by_module_name;
45 gchar *obsoleted_by_module_stream;
46 };
47
48 G_DEFINE_TYPE (ModulemdObsoletes, modulemd_obsoletes, G_TYPE_OBJECT)
49
50 enum
51 {
52 PROP_0,
53
54 PROP_MDVERSION,
55 PROP_MODIFIED,
56 PROP_RESET,
57 PROP_MODULE_NAME,
58 PROP_MODULE_STREAM,
59 PROP_MODULE_CONTEXT,
60 PROP_EOL_DATE,
61 PROP_MESSAGE,
62 PROP_OBSOLETED_BY_MODULE_NAME,
63 PROP_OBSOLETED_BY_MODULE_STREAM,
64
65 N_PROPS
66 };
67
68 static GParamSpec *properties[N_PROPS];
69
70 ModulemdObsoletes *
modulemd_obsoletes_new(guint64 mdversion,guint64 modified,const gchar * module_name,const gchar * module_stream,const gchar * message)71 modulemd_obsoletes_new (guint64 mdversion,
72 guint64 modified,
73 const gchar *module_name,
74 const gchar *module_stream,
75 const gchar *message)
76 {
77 // clang-format off
78 return g_object_new (MODULEMD_TYPE_OBSOLETES,
79 "mdversion", mdversion,
80 "modified", modified,
81 "module-name", module_name,
82 "module-stream", module_stream,
83 "message", message,
84 NULL);
85 // clang-format on
86 }
87
88
89 ModulemdObsoletes *
modulemd_obsoletes_copy(ModulemdObsoletes * self)90 modulemd_obsoletes_copy (ModulemdObsoletes *self)
91 {
92 g_autoptr (ModulemdObsoletes) o = NULL;
93
94 g_return_val_if_fail (MODULEMD_IS_OBSOLETES (self), NULL);
95
96
97 o = modulemd_obsoletes_new (modulemd_obsoletes_get_mdversion (self),
98 modulemd_obsoletes_get_modified (self),
99 modulemd_obsoletes_get_module_name (self),
100 modulemd_obsoletes_get_module_stream (self),
101 modulemd_obsoletes_get_message (self));
102 modulemd_obsoletes_set_module_context (
103 o, modulemd_obsoletes_get_module_context (self));
104 modulemd_obsoletes_set_reset (o, modulemd_obsoletes_get_reset (self));
105 modulemd_obsoletes_set_eol_date (o, modulemd_obsoletes_get_eol_date (self));
106 modulemd_obsoletes_set_obsoleted_by_module_name (
107 o, modulemd_obsoletes_get_obsoleted_by_module_name (self));
108 modulemd_obsoletes_set_obsoleted_by_module_stream (
109 o, modulemd_obsoletes_get_obsoleted_by_module_stream (self));
110
111 return g_steal_pointer (&o);
112 }
113
114 gboolean
modulemd_obsoletes_validate(ModulemdObsoletes * self,GError ** error)115 modulemd_obsoletes_validate (ModulemdObsoletes *self, GError **error)
116 {
117 g_return_val_if_fail (MODULEMD_IS_OBSOLETES (self), FALSE);
118 guint64 mdversion = modulemd_obsoletes_get_mdversion (self);
119
120 if (!mdversion)
121 {
122 g_set_error_literal (error,
123 MODULEMD_ERROR,
124 MMD_ERROR_VALIDATE,
125 "Metadata version is unset.");
126 return FALSE;
127 }
128 if (mdversion > MD_OBSOLETES_VERSION_LATEST)
129 {
130 g_set_error (error,
131 MODULEMD_ERROR,
132 MMD_ERROR_VALIDATE,
133 "Metadata version unknown: %" PRIu64 ".",
134 mdversion);
135 return FALSE;
136 }
137
138 if (modulemd_obsoletes_get_modified (self) == 0)
139 {
140 g_set_error_literal (error,
141 MODULEMD_ERROR,
142 MMD_ERROR_VALIDATE,
143 "Obsoletes modified is empty.");
144 return FALSE;
145 }
146
147 if (!g_strcmp0 (modulemd_obsoletes_get_module_name (self),
148 O_PLACEHOLDER_STRING) ||
149 modulemd_obsoletes_get_module_name (self)[0] == '\0')
150 {
151 g_set_error_literal (error,
152 MODULEMD_ERROR,
153 MMD_ERROR_VALIDATE,
154 "Obsoletes module name is unset.");
155 return FALSE;
156 }
157
158 if (!g_strcmp0 (modulemd_obsoletes_get_module_stream (self),
159 O_PLACEHOLDER_STRING) ||
160 modulemd_obsoletes_get_module_stream (self)[0] == '\0')
161 {
162 g_set_error_literal (error,
163 MODULEMD_ERROR,
164 MMD_ERROR_VALIDATE,
165 "Obsoletes stream is unset.");
166 return FALSE;
167 }
168
169 if (!g_strcmp0 (modulemd_obsoletes_get_message (self),
170 O_PLACEHOLDER_STRING) ||
171 !g_strcmp0 (modulemd_obsoletes_get_message (self), O_DEFAULT_STRING) ||
172 modulemd_obsoletes_get_message (self)[0] == '\0')
173 {
174 g_set_error_literal (error,
175 MODULEMD_ERROR,
176 MMD_ERROR_VALIDATE,
177 "Obsoletes message is unset.");
178 return FALSE;
179 }
180
181 /* It should not be possible to set reset and eol_date
182 * at the same time */
183 if (modulemd_obsoletes_get_reset (self) &&
184 modulemd_obsoletes_get_eol_date (self))
185 {
186 g_set_error_literal (
187 error,
188 MODULEMD_ERROR,
189 MMD_ERROR_VALIDATE,
190 "Obsoletes cannot have both eol_date and reset attributes set.");
191 return FALSE;
192 }
193 /* It should not be possible to set reset and obsoleted_by*
194 * at the same time */
195 if (modulemd_obsoletes_get_reset (self) &&
196 (modulemd_obsoletes_get_obsoleted_by_module_name (self) ||
197 modulemd_obsoletes_get_obsoleted_by_module_stream (self)))
198 {
199 g_set_error_literal (
200 error,
201 MODULEMD_ERROR,
202 MMD_ERROR_VALIDATE,
203 "Obsoletes cannot have both obsoleted_by and reset attributes set.");
204 return FALSE;
205 }
206
207 if ((modulemd_obsoletes_get_obsoleted_by_module_name (self) &&
208 !modulemd_obsoletes_get_obsoleted_by_module_stream (self)) ||
209 (!modulemd_obsoletes_get_obsoleted_by_module_name (self) &&
210 modulemd_obsoletes_get_obsoleted_by_module_stream (self)))
211 {
212 g_set_error_literal (
213 error,
214 MODULEMD_ERROR,
215 MMD_ERROR_VALIDATE,
216 "Obsoletes obsoleted by module name and module stream "
217 "have to be set together.");
218 return FALSE;
219 }
220
221 return TRUE;
222 }
223
224 static void
modulemd_obsoletes_finalize(GObject * object)225 modulemd_obsoletes_finalize (GObject *object)
226 {
227 ModulemdObsoletes *self = (ModulemdObsoletes *)object;
228
229 g_clear_pointer (&self->module_name, g_free);
230 g_clear_pointer (&self->module_stream, g_free);
231 g_clear_pointer (&self->module_context, g_free);
232 g_clear_pointer (&self->message, g_free);
233 g_clear_pointer (&self->obsoleted_by_module_name, g_free);
234 g_clear_pointer (&self->obsoleted_by_module_stream, g_free);
235
236 G_OBJECT_CLASS (modulemd_obsoletes_parent_class)->finalize (object);
237 }
238
239 guint64
modulemd_obsoletes_get_mdversion(ModulemdObsoletes * self)240 modulemd_obsoletes_get_mdversion (ModulemdObsoletes *self)
241 {
242 return self->mdversion;
243 }
244
245
246 guint64
modulemd_obsoletes_get_modified(ModulemdObsoletes * self)247 modulemd_obsoletes_get_modified (ModulemdObsoletes *self)
248 {
249 return self->modified;
250 }
251
252
253 gboolean
modulemd_obsoletes_get_reset(ModulemdObsoletes * self)254 modulemd_obsoletes_get_reset (ModulemdObsoletes *self)
255 {
256 return self->reset;
257 }
258
259
260 const gchar *
modulemd_obsoletes_get_module_name(ModulemdObsoletes * self)261 modulemd_obsoletes_get_module_name (ModulemdObsoletes *self)
262 {
263 return self->module_name;
264 }
265
266
267 const gchar *
modulemd_obsoletes_get_module_stream(ModulemdObsoletes * self)268 modulemd_obsoletes_get_module_stream (ModulemdObsoletes *self)
269 {
270 return self->module_stream;
271 }
272
273
274 const gchar *
modulemd_obsoletes_get_module_context(ModulemdObsoletes * self)275 modulemd_obsoletes_get_module_context (ModulemdObsoletes *self)
276 {
277 return self->module_context;
278 }
279
280
281 guint64
modulemd_obsoletes_get_eol_date(ModulemdObsoletes * self)282 modulemd_obsoletes_get_eol_date (ModulemdObsoletes *self)
283 {
284 return self->eol_date;
285 }
286
287
288 const gchar *
modulemd_obsoletes_get_message(ModulemdObsoletes * self)289 modulemd_obsoletes_get_message (ModulemdObsoletes *self)
290 {
291 return self->message;
292 }
293
294
295 const gchar *
modulemd_obsoletes_get_obsoleted_by_module_name(ModulemdObsoletes * self)296 modulemd_obsoletes_get_obsoleted_by_module_name (ModulemdObsoletes *self)
297 {
298 return self->obsoleted_by_module_name;
299 }
300
301
302 const gchar *
modulemd_obsoletes_get_obsoleted_by_module_stream(ModulemdObsoletes * self)303 modulemd_obsoletes_get_obsoleted_by_module_stream (ModulemdObsoletes *self)
304 {
305 return self->obsoleted_by_module_stream;
306 }
307
308
309 static void
modulemd_obsoletes_set_mdversion(ModulemdObsoletes * self,guint64 mdversion)310 modulemd_obsoletes_set_mdversion (ModulemdObsoletes *self, guint64 mdversion)
311 {
312 g_return_if_fail (MODULEMD_IS_OBSOLETES (self));
313 g_return_if_fail (mdversion != 0);
314
315 self->mdversion = mdversion;
316
317 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MDVERSION]);
318 }
319
320 void
modulemd_obsoletes_set_modified(ModulemdObsoletes * self,guint64 modified)321 modulemd_obsoletes_set_modified (ModulemdObsoletes *self, guint64 modified)
322 {
323 g_return_if_fail (MODULEMD_IS_OBSOLETES (self));
324
325 self->modified = modified;
326
327 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODIFIED]);
328 }
329
330
331 void
modulemd_obsoletes_set_reset(ModulemdObsoletes * self,gboolean reset)332 modulemd_obsoletes_set_reset (ModulemdObsoletes *self, gboolean reset)
333 {
334 g_return_if_fail (MODULEMD_IS_OBSOLETES (self));
335
336 self->reset = reset;
337
338 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_RESET]);
339 }
340
341
342 static void
modulemd_obsoletes_set_module_name(ModulemdObsoletes * self,const gchar * module_name)343 modulemd_obsoletes_set_module_name (ModulemdObsoletes *self,
344 const gchar *module_name)
345 {
346 g_return_if_fail (MODULEMD_IS_OBSOLETES (self));
347 g_return_if_fail (module_name);
348 g_return_if_fail (g_strcmp0 (module_name, O_DEFAULT_STRING));
349
350 g_clear_pointer (&self->module_name, g_free);
351 self->module_name = g_strdup (module_name);
352
353 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODULE_NAME]);
354 }
355
356
357 static void
modulemd_obsoletes_set_module_stream(ModulemdObsoletes * self,const gchar * module_stream)358 modulemd_obsoletes_set_module_stream (ModulemdObsoletes *self,
359 const gchar *module_stream)
360 {
361 g_return_if_fail (MODULEMD_IS_OBSOLETES (self));
362 g_return_if_fail (module_stream);
363 g_return_if_fail (g_strcmp0 (module_stream, O_DEFAULT_STRING));
364
365 g_clear_pointer (&self->module_stream, g_free);
366 self->module_stream = g_strdup (module_stream);
367
368 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODULE_STREAM]);
369 }
370
371
372 void
modulemd_obsoletes_set_module_context(ModulemdObsoletes * self,const gchar * module_context)373 modulemd_obsoletes_set_module_context (ModulemdObsoletes *self,
374 const gchar *module_context)
375 {
376 g_return_if_fail (MODULEMD_IS_OBSOLETES (self));
377
378 g_clear_pointer (&self->module_context, g_free);
379 self->module_context = g_strdup (module_context);
380
381 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODULE_CONTEXT]);
382 }
383
384 void
modulemd_obsoletes_set_eol_date(ModulemdObsoletes * self,guint64 eol_date)385 modulemd_obsoletes_set_eol_date (ModulemdObsoletes *self, guint64 eol_date)
386 {
387 g_return_if_fail (MODULEMD_IS_OBSOLETES (self));
388
389 self->eol_date = eol_date;
390
391 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_EOL_DATE]);
392 }
393
394
395 void
modulemd_obsoletes_set_message(ModulemdObsoletes * self,const gchar * message)396 modulemd_obsoletes_set_message (ModulemdObsoletes *self, const gchar *message)
397 {
398 g_return_if_fail (MODULEMD_IS_OBSOLETES (self));
399 g_return_if_fail (message);
400
401 g_clear_pointer (&self->message, g_free);
402 self->message = g_strdup (message);
403
404 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MESSAGE]);
405 }
406
407 void
modulemd_obsoletes_set_obsoleted_by_module_name(ModulemdObsoletes * self,const gchar * obsoleted_by_module_name)408 modulemd_obsoletes_set_obsoleted_by_module_name (
409 ModulemdObsoletes *self, const gchar *obsoleted_by_module_name)
410 {
411 g_return_if_fail (MODULEMD_IS_OBSOLETES (self));
412
413 g_clear_pointer (&self->obsoleted_by_module_name, g_free);
414 self->obsoleted_by_module_name = g_strdup (obsoleted_by_module_name);
415
416 g_object_notify_by_pspec (G_OBJECT (self),
417 properties[PROP_OBSOLETED_BY_MODULE_NAME]);
418 }
419
420 void
modulemd_obsoletes_set_obsoleted_by_module_stream(ModulemdObsoletes * self,const gchar * obsoleted_by_module_stream)421 modulemd_obsoletes_set_obsoleted_by_module_stream (
422 ModulemdObsoletes *self, const gchar *obsoleted_by_module_stream)
423 {
424 g_return_if_fail (MODULEMD_IS_OBSOLETES (self));
425
426 g_clear_pointer (&self->obsoleted_by_module_stream, g_free);
427 self->obsoleted_by_module_stream = g_strdup (obsoleted_by_module_stream);
428
429 g_object_notify_by_pspec (G_OBJECT (self),
430 properties[PROP_OBSOLETED_BY_MODULE_STREAM]);
431 }
432
433 void
modulemd_obsoletes_set_obsoleted_by(ModulemdObsoletes * self,const gchar * obsoleted_by_module_name,const gchar * obsoleted_by_module_stream)434 modulemd_obsoletes_set_obsoleted_by (ModulemdObsoletes *self,
435 const gchar *obsoleted_by_module_name,
436 const gchar *obsoleted_by_module_stream)
437 {
438 g_return_if_fail (MODULEMD_IS_OBSOLETES (self));
439
440 modulemd_obsoletes_set_obsoleted_by_module_name (self,
441 obsoleted_by_module_name);
442 modulemd_obsoletes_set_obsoleted_by_module_stream (
443 self, obsoleted_by_module_stream);
444 }
445
446
447 static void
modulemd_obsoletes_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)448 modulemd_obsoletes_get_property (GObject *object,
449 guint prop_id,
450 GValue *value,
451 GParamSpec *pspec)
452 {
453 ModulemdObsoletes *self = MODULEMD_OBSOLETES (object);
454
455 switch (prop_id)
456 {
457 case PROP_MDVERSION:
458 g_value_set_uint64 (value, modulemd_obsoletes_get_mdversion (self));
459 break;
460 case PROP_MODIFIED:
461 g_value_set_uint64 (value, modulemd_obsoletes_get_modified (self));
462 break;
463 case PROP_RESET:
464 g_value_set_boolean (value, modulemd_obsoletes_get_reset (self));
465 break;
466 case PROP_MODULE_NAME:
467 g_value_set_string (value, modulemd_obsoletes_get_module_name (self));
468 break;
469 case PROP_MODULE_STREAM:
470 g_value_set_string (value, modulemd_obsoletes_get_module_stream (self));
471 break;
472 case PROP_MODULE_CONTEXT:
473 g_value_set_string (value, modulemd_obsoletes_get_module_context (self));
474 break;
475 case PROP_EOL_DATE:
476 g_value_set_uint64 (value, modulemd_obsoletes_get_eol_date (self));
477 break;
478 case PROP_MESSAGE:
479 g_value_set_string (value, modulemd_obsoletes_get_message (self));
480 break;
481 case PROP_OBSOLETED_BY_MODULE_NAME:
482 g_value_set_string (
483 value, modulemd_obsoletes_get_obsoleted_by_module_name (self));
484 break;
485 case PROP_OBSOLETED_BY_MODULE_STREAM:
486 g_value_set_string (
487 value, modulemd_obsoletes_get_obsoleted_by_module_stream (self));
488 break;
489 default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
490 }
491 }
492
493
494 static void
modulemd_obsoletes_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)495 modulemd_obsoletes_set_property (GObject *object,
496 guint prop_id,
497 const GValue *value,
498 GParamSpec *pspec)
499 {
500 ModulemdObsoletes *self = MODULEMD_OBSOLETES (object);
501
502 switch (prop_id)
503 {
504 case PROP_MDVERSION:
505 modulemd_obsoletes_set_mdversion (self, g_value_get_uint64 (value));
506 break;
507 case PROP_MODIFIED:
508 modulemd_obsoletes_set_modified (self, g_value_get_uint64 (value));
509 break;
510 case PROP_RESET:
511 modulemd_obsoletes_set_reset (self, g_value_get_boolean (value));
512 break;
513 case PROP_MODULE_NAME:
514 modulemd_obsoletes_set_module_name (self, g_value_get_string (value));
515 break;
516 case PROP_MODULE_STREAM:
517 modulemd_obsoletes_set_module_stream (self, g_value_get_string (value));
518 break;
519 case PROP_MODULE_CONTEXT:
520 modulemd_obsoletes_set_module_context (self, g_value_get_string (value));
521 break;
522 case PROP_EOL_DATE:
523 modulemd_obsoletes_set_eol_date (self, g_value_get_uint64 (value));
524 break;
525 case PROP_MESSAGE:
526 modulemd_obsoletes_set_message (self, g_value_get_string (value));
527 break;
528 case PROP_OBSOLETED_BY_MODULE_NAME:
529 modulemd_obsoletes_set_obsoleted_by_module_name (
530 self, g_value_get_string (value));
531 break;
532 case PROP_OBSOLETED_BY_MODULE_STREAM:
533 modulemd_obsoletes_set_obsoleted_by_module_stream (
534 self, g_value_get_string (value));
535 break;
536 default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
537 }
538 }
539
540 static void
modulemd_obsoletes_class_init(ModulemdObsoletesClass * klass)541 modulemd_obsoletes_class_init (ModulemdObsoletesClass *klass)
542 {
543 GObjectClass *object_class = G_OBJECT_CLASS (klass);
544
545 object_class->finalize = modulemd_obsoletes_finalize;
546 object_class->get_property = modulemd_obsoletes_get_property;
547 object_class->set_property = modulemd_obsoletes_set_property;
548
549 properties[PROP_MDVERSION] = g_param_spec_uint64 (
550 "mdversion",
551 "Metadata Version",
552 "The metadata version of this obsoletes object.",
553 0,
554 G_MAXUINT64,
555 0,
556 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
557
558 properties[PROP_MODIFIED] = g_param_spec_uint64 (
559 "modified",
560 "Modified",
561 "The last modified time represented as a 64-bit integer "
562 "(such as 201807011200)",
563 0,
564 G_MAXUINT64,
565 0,
566 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
567
568 properties[PROP_MODULE_NAME] = g_param_spec_string (
569 "module-name",
570 "Module name",
571 "The name of the module to which this obsoletes applies.",
572 O_DEFAULT_STRING,
573 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
574
575 properties[PROP_RESET] = g_param_spec_boolean (
576 "override-previous",
577 "Override previous",
578 "A boolean option to cancel/reset all previously specified obsoletes.",
579 FALSE,
580 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
581
582 properties[PROP_MODULE_STREAM] = g_param_spec_string (
583 "module-stream",
584 "Module stream",
585 "The name of the module stream to which this obsoletes applies.",
586 O_DEFAULT_STRING,
587 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
588
589 properties[PROP_MODULE_CONTEXT] = g_param_spec_string (
590 "module-context",
591 "Module context",
592 "The name of the module context to which this obsoletes applies.",
593 NULL,
594 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
595
596 properties[PROP_EOL_DATE] = g_param_spec_uint64 (
597 "eol-date",
598 "EOL date",
599 "A string representing UTC date in ISO 8601 format: YYYY-MM-DDTHH:MMZ",
600 0,
601 G_MAXUINT64,
602 0,
603 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
604
605 properties[PROP_MESSAGE] = g_param_spec_string (
606 "message",
607 "Message",
608 "A string describing the change, reason, etc.",
609 O_DEFAULT_STRING,
610 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
611
612 properties[PROP_OBSOLETED_BY_MODULE_NAME] = g_param_spec_string (
613 "obsoleted-by-module-name",
614 "Obsoleted by module name",
615 "Name of the module that obsoletes this one.",
616 NULL,
617 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
618
619 properties[PROP_OBSOLETED_BY_MODULE_STREAM] = g_param_spec_string (
620 "obsoleted-by-module-stream",
621 "Obsoleted by module stream",
622 "Stream of the module that obsoletes this one.",
623 NULL,
624 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
625
626 g_object_class_install_properties (object_class, N_PROPS, properties);
627 }
628
629 static void
modulemd_obsoletes_init(ModulemdObsoletes * self)630 modulemd_obsoletes_init (ModulemdObsoletes *self)
631 {
632 }
633
634 /* === YAML Functions === */
635 static gboolean
modulemd_obsoletes_parse_obsoleted_by(yaml_parser_t * parser,ModulemdObsoletes * o,gboolean strict,GError ** error)636 modulemd_obsoletes_parse_obsoleted_by (yaml_parser_t *parser,
637 ModulemdObsoletes *o,
638 gboolean strict,
639 GError **error)
640 {
641 MODULEMD_INIT_TRACE ();
642 MMD_INIT_YAML_EVENT (event);
643 g_autoptr (GError) nested_error = NULL;
644 gchar *value = NULL;
645 gboolean done = FALSE;
646
647 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
648 YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
649 if (event.type != YAML_MAPPING_START_EVENT)
650 {
651 MMD_YAML_ERROR_EVENT_EXIT_BOOL (
652 error, event, "Missing mapping in obsoletes obsoleted_by.");
653 }
654
655 while (!done)
656 {
657 YAML_PARSER_PARSE_WITH_EXIT_BOOL (parser, &event, error);
658 switch (event.type)
659 {
660 case YAML_MAPPING_END_EVENT: done = TRUE; break;
661
662 case YAML_SCALAR_EVENT:
663 if (g_str_equal (event.data.scalar.value, "module"))
664 {
665 if (modulemd_obsoletes_get_obsoleted_by_module_name (o))
666 {
667 /* We already have a module name. It should not appear
668 * twice in the same document.
669 */
670 MMD_YAML_ERROR_EVENT_EXIT_BOOL (
671 error,
672 event,
673 "Obsoleted by module name encountered twice.");
674 }
675
676 value = modulemd_yaml_parse_string (parser, &nested_error);
677 if (!value)
678 {
679 MMD_YAML_ERROR_EVENT_EXIT_BOOL (
680 error,
681 event,
682 "Failed to parse module name in obsoletes obsoleted_by "
683 "data: %s",
684 nested_error->message);
685 }
686 modulemd_obsoletes_set_obsoleted_by_module_name (o, value);
687 g_clear_pointer (&value, g_free);
688 }
689
690 if (g_str_equal (event.data.scalar.value, "stream"))
691 {
692 if (modulemd_obsoletes_get_obsoleted_by_module_stream (o))
693 {
694 /* We already have a module stream. It should not appear
695 * twice in the same document.
696 */
697 MMD_YAML_ERROR_EVENT_EXIT_BOOL (
698 error,
699 event,
700 "Obsoleted by module stream encountered twice.");
701 }
702
703 value = modulemd_yaml_parse_string (parser, &nested_error);
704 if (!value)
705 {
706 MMD_YAML_ERROR_EVENT_EXIT_BOOL (
707 error,
708 event,
709 "Failed to parse module stream in obsoletes obsoleted_by "
710 "data: %s",
711 nested_error->message);
712 }
713 modulemd_obsoletes_set_obsoleted_by_module_stream (o, value);
714 g_clear_pointer (&value, g_free);
715 }
716 break;
717
718 default:
719 MMD_YAML_ERROR_EVENT_EXIT_BOOL (
720 error, event, "Unexpected YAML event in obsoletes obsoleted_by.");
721 break;
722 }
723 yaml_event_delete (&event);
724 }
725
726 return TRUE;
727 }
728
729 ModulemdObsoletes *
modulemd_obsoletes_parse_yaml(ModulemdSubdocumentInfo * subdoc,gboolean strict,GError ** error)730 modulemd_obsoletes_parse_yaml (ModulemdSubdocumentInfo *subdoc,
731 gboolean strict,
732 GError **error)
733 {
734 MODULEMD_INIT_TRACE ();
735 MMD_INIT_YAML_PARSER (parser);
736 MMD_INIT_YAML_EVENT (event);
737 g_autoptr (GError) nested_error = NULL;
738 gboolean done = FALSE;
739
740 g_autofree gchar *value = NULL;
741 g_autofree gchar *obs_by_mod_name = NULL;
742 g_autofree gchar *obs_by_mod_stream = NULL;
743 guint64 modified;
744 guint64 eol_date;
745 gboolean reset;
746
747 g_autoptr (ModulemdObsoletes) o = NULL;
748
749 guint64 mdversion = modulemd_subdocument_info_get_mdversion (subdoc);
750
751 if (!modulemd_subdocument_info_get_data_parser (
752 subdoc, &parser, strict, error))
753 {
754 g_debug ("get_data_parser() failed: %s", (*error)->message);
755 return NULL;
756 }
757
758 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
759
760 /* Create an obsoletes with placeholder values. We'll verify that this has been
761 * changed before we return it. This is because we can't guarantee that we
762 * will get the actual values from the YAML before reading any of the other
763 * data, but it's easier to process the rest of the contents with the
764 * constructed object.
765 */
766 o = modulemd_obsoletes_new (mdversion,
767 0,
768 O_PLACEHOLDER_STRING,
769 O_PLACEHOLDER_STRING,
770 O_PLACEHOLDER_STRING);
771
772 YAML_PARSER_PARSE_WITH_EXIT (&parser, &event, error);
773 if (event.type != YAML_MAPPING_START_EVENT)
774 {
775 MMD_YAML_ERROR_EVENT_EXIT (
776 error, event, "Missing START EVENT mapping in obsoletes data entry");
777 }
778
779 //parsing loop
780 while (!done)
781 {
782 YAML_PARSER_PARSE_WITH_EXIT (&parser, &event, error);
783
784 switch (event.type)
785 {
786 case YAML_MAPPING_END_EVENT: done = TRUE; break;
787
788 case YAML_SCALAR_EVENT:
789 if (g_str_equal (event.data.scalar.value, "module"))
790 {
791 if (!g_str_equal (modulemd_obsoletes_get_module_name (o),
792 O_PLACEHOLDER_STRING))
793 {
794 /* The module name was set earlier, which means it is
795 * not expected here
796 */
797 MMD_YAML_ERROR_EVENT_EXIT (
798 error, event, "Module name encountered twice");
799 }
800 value = modulemd_yaml_parse_string (&parser, &nested_error);
801 if (!value)
802 {
803 MMD_YAML_ERROR_EVENT_EXIT (
804 error,
805 event,
806 "Failed to parse module name in obsoletes data: %s",
807 nested_error->message);
808 }
809
810 /* Use a private internal function to set the module_name.
811 * External consumers should never be allowed to change this
812 * value, but we need to be able to modify the placeholder.
813 */
814 modulemd_obsoletes_set_module_name (o, value);
815 g_clear_pointer (&value, g_free);
816 }
817 else if (g_str_equal (event.data.scalar.value, "stream"))
818 {
819 if (!g_str_equal (modulemd_obsoletes_get_module_stream (o),
820 O_PLACEHOLDER_STRING))
821 {
822 MMD_YAML_ERROR_EVENT_EXIT (
823 error, event, "Module stream encountered twice");
824 }
825 value = modulemd_yaml_parse_string (&parser, &nested_error);
826 if (!value)
827 {
828 MMD_YAML_ERROR_EVENT_EXIT (
829 error,
830 event,
831 "Failed to parse module stream in obsoletes data: %s",
832 nested_error->message);
833 }
834
835 modulemd_obsoletes_set_module_stream (o, value);
836 g_clear_pointer (&value, g_free);
837 }
838 else if (g_str_equal (event.data.scalar.value, "context"))
839 {
840 if (modulemd_obsoletes_get_module_context (o))
841 {
842 MMD_YAML_ERROR_EVENT_EXIT (
843 error, event, "Module context encountered twice");
844 }
845 value = modulemd_yaml_parse_string (&parser, &nested_error);
846 if (!value)
847 {
848 MMD_YAML_ERROR_EVENT_EXIT (
849 error,
850 event,
851 "Failed to parse module context in obsoletes data: %s",
852 nested_error->message);
853 }
854
855 modulemd_obsoletes_set_module_context (o, value);
856 g_clear_pointer (&value, g_free);
857 }
858 else if (g_str_equal (event.data.scalar.value, "modified"))
859 {
860 value = modulemd_yaml_parse_string (&parser, &nested_error);
861 if (nested_error)
862 {
863 MMD_YAML_ERROR_EVENT_EXIT (
864 error,
865 event,
866 "Failed to parse modified in obsoletes data: %s",
867 nested_error->message);
868 }
869 modified = modulemd_iso8601date_to_guint64 (value);
870 if (modified == 0)
871 {
872 MMD_YAML_ERROR_EVENT_EXIT (
873 error,
874 event,
875 "Failed to parse UTC date in ISO 8601 format: "
876 "YYYY-MM-DDTHH:MMZ modified in eol data: %s",
877 value);
878 }
879
880 modulemd_obsoletes_set_modified (o, modified);
881 g_clear_pointer (&value, g_free);
882 }
883 else if (g_str_equal (event.data.scalar.value, "eol_date"))
884 {
885 value = modulemd_yaml_parse_string (&parser, &nested_error);
886 if (nested_error)
887 {
888 MMD_YAML_ERROR_EVENT_EXIT (
889 error,
890 event,
891 "Failed to parse eol_date in obsoletes data: %s",
892 nested_error->message);
893 }
894
895 eol_date = modulemd_iso8601date_to_guint64 (value);
896 if (eol_date == 0)
897 {
898 MMD_YAML_ERROR_EVENT_EXIT (
899 error,
900 event,
901 "Failed to parse UTC date in ISO 8601 format: "
902 "YYYY-MM-DD[T ]HH:MMZ eol_date in obsoletes data: %s",
903 value);
904 }
905
906 modulemd_obsoletes_set_eol_date (o, eol_date);
907 g_clear_pointer (&value, g_free);
908 }
909 else if (g_str_equal (event.data.scalar.value, "reset"))
910 {
911 reset = modulemd_yaml_parse_bool (&parser, &nested_error);
912 if (nested_error)
913 {
914 MMD_YAML_ERROR_EVENT_EXIT (
915 error,
916 event,
917 "Failed to parse reset in obsoletes data: %s",
918 nested_error->message);
919 }
920
921 modulemd_obsoletes_set_reset (o, reset);
922 }
923 else if (g_str_equal (event.data.scalar.value, "message"))
924 {
925 if (!g_str_equal (modulemd_obsoletes_get_message (o),
926 O_PLACEHOLDER_STRING))
927 {
928 MMD_YAML_ERROR_EVENT_EXIT (
929 error, event, "Module message encountered twice");
930 }
931 value = modulemd_yaml_parse_string (&parser, &nested_error);
932 if (!value)
933 {
934 MMD_YAML_ERROR_EVENT_EXIT (
935 error,
936 event,
937 "Failed to parse message in obsoletes data: %s",
938 nested_error->message);
939 }
940
941 modulemd_obsoletes_set_message (o, value);
942 g_clear_pointer (&value, g_free);
943 }
944 else if (g_str_equal (event.data.scalar.value, "obsoleted_by"))
945 {
946 if (!modulemd_obsoletes_parse_obsoleted_by (
947 &parser, o, strict, &nested_error))
948 {
949 g_propagate_error (error, g_steal_pointer (&nested_error));
950 return NULL;
951 }
952 }
953 else
954 {
955 SKIP_UNKNOWN (&parser,
956 NULL,
957 "Unexpected key in obsoletes data: %s",
958 (const gchar *)event.data.scalar.value);
959 break;
960 }
961 break;
962
963 default:
964 MMD_YAML_ERROR_EVENT_EXIT (
965 error,
966 event,
967 "Unexpected YAML event %s in obsoletes data",
968 mmd_yaml_get_event_name (event.type));
969 break;
970 }
971
972 yaml_event_delete (&event);
973 }
974
975 if (!modulemd_obsoletes_validate (o, &nested_error))
976 {
977 g_propagate_error (error, g_steal_pointer (&nested_error));
978 return NULL;
979 }
980
981 return g_steal_pointer (&o);
982 }
983
984
985 static gboolean
modulemd_obsoletes_emit_obsoleted_by(ModulemdObsoletes * self,yaml_emitter_t * emitter,GError ** error)986 modulemd_obsoletes_emit_obsoleted_by (ModulemdObsoletes *self,
987 yaml_emitter_t *emitter,
988 GError **error)
989 {
990 /* Start the "obsoleted_by:" section */
991 if (!mmd_emitter_scalar (
992 emitter, "obsoleted_by", YAML_PLAIN_SCALAR_STYLE, error))
993 {
994 return FALSE;
995 }
996
997 /* Start the mapping for "obsoleted_by:" */
998 if (!mmd_emitter_start_mapping (emitter, YAML_BLOCK_MAPPING_STYLE, error))
999 {
1000 return FALSE;
1001 }
1002
1003 /* The module name is mandatory if already in obsoleted_by */
1004 if (!mmd_emitter_scalar (emitter, "module", YAML_PLAIN_SCALAR_STYLE, error))
1005 {
1006 return FALSE;
1007 }
1008
1009 if (!mmd_emitter_scalar (emitter,
1010 modulemd_obsoletes_get_obsoleted_by_module_name (
1011 MODULEMD_OBSOLETES (self)),
1012 YAML_PLAIN_SCALAR_STYLE,
1013 error))
1014 {
1015 return FALSE;
1016 }
1017
1018 /* The module stream is mandatory if already in obsoleted_by */
1019 if (!mmd_emitter_scalar (emitter, "stream", YAML_PLAIN_SCALAR_STYLE, error))
1020 {
1021 return FALSE;
1022 }
1023
1024 if (!mmd_emitter_scalar (emitter,
1025 modulemd_obsoletes_get_obsoleted_by_module_stream (
1026 MODULEMD_OBSOLETES (self)),
1027 YAML_DOUBLE_QUOTED_SCALAR_STYLE,
1028 error))
1029 {
1030 return FALSE;
1031 }
1032
1033 /* End the mapping for "obsoleted_by:" */
1034 if (!mmd_emitter_end_mapping (emitter, error))
1035 {
1036 return FALSE;
1037 }
1038 return TRUE;
1039 }
1040
1041
1042 gboolean
modulemd_obsoletes_emit_yaml(ModulemdObsoletes * self,yaml_emitter_t * emitter,GError ** error)1043 modulemd_obsoletes_emit_yaml (ModulemdObsoletes *self,
1044 yaml_emitter_t *emitter,
1045 GError **error)
1046 {
1047 MODULEMD_INIT_TRACE ();
1048 g_autoptr (GError) nested_error = NULL;
1049 guint64 eol_date;
1050 g_autofree gchar *modified_string = NULL;
1051 g_autofree gchar *eol_date_string = NULL;
1052 const gchar *module_context = NULL;
1053
1054 if (!modulemd_obsoletes_validate (MODULEMD_OBSOLETES (self), &nested_error))
1055 {
1056 /* Validation failed */
1057 g_propagate_prefixed_error (error,
1058 g_steal_pointer (&nested_error),
1059 "Obsoletes object failed validation: ");
1060 return FALSE;
1061 }
1062
1063 /* First emit the standard document headers */
1064 if (!modulemd_yaml_emit_document_headers (
1065 emitter,
1066 MODULEMD_YAML_DOC_OBSOLETES,
1067 modulemd_obsoletes_get_mdversion (MODULEMD_OBSOLETES (self)),
1068 error))
1069 {
1070 return FALSE;
1071 }
1072
1073 /* Start the data: section mapping */
1074 if (!mmd_emitter_start_mapping (emitter, YAML_BLOCK_MAPPING_STYLE, error))
1075 {
1076 return FALSE;
1077 }
1078
1079 /* Fill in the default data */
1080
1081 /* The modified field is mandatory */
1082 if (!mmd_emitter_scalar (
1083 emitter, "modified", YAML_PLAIN_SCALAR_STYLE, error))
1084 {
1085 return FALSE;
1086 }
1087 modified_string = modulemd_guint64_to_iso8601date (
1088 modulemd_obsoletes_get_modified (MODULEMD_OBSOLETES (self)));
1089 if (!modified_string)
1090 {
1091 g_set_error (
1092 error,
1093 MODULEMD_ERROR,
1094 MMD_ERROR_VALIDATE,
1095 "Cannot convert modified date: %" PRIu64 " to iso8601 date.",
1096 modulemd_obsoletes_get_modified (MODULEMD_OBSOLETES (self)));
1097 return FALSE;
1098 }
1099 if (!mmd_emitter_scalar (
1100 emitter, modified_string, YAML_PLAIN_SCALAR_STYLE, error))
1101 {
1102 return FALSE;
1103 }
1104
1105 /* Only output reset if it's TRUE */
1106 if (modulemd_obsoletes_get_reset (self))
1107 {
1108 EMIT_KEY_VALUE (emitter, error, "reset", "true");
1109 }
1110
1111 /* The module name is mandatory */
1112 if (!mmd_emitter_scalar (emitter, "module", YAML_PLAIN_SCALAR_STYLE, error))
1113 {
1114 return FALSE;
1115 }
1116
1117 if (!mmd_emitter_scalar (
1118 emitter,
1119 modulemd_obsoletes_get_module_name (MODULEMD_OBSOLETES (self)),
1120 YAML_PLAIN_SCALAR_STYLE,
1121 error))
1122 {
1123 return FALSE;
1124 }
1125
1126 /* The module stream is mandatory */
1127 if (!mmd_emitter_scalar (emitter, "stream", YAML_PLAIN_SCALAR_STYLE, error))
1128 {
1129 return FALSE;
1130 }
1131
1132 if (!mmd_emitter_scalar (
1133 emitter,
1134 modulemd_obsoletes_get_module_stream (MODULEMD_OBSOLETES (self)),
1135 YAML_DOUBLE_QUOTED_SCALAR_STYLE,
1136 error))
1137 {
1138 return FALSE;
1139 }
1140
1141 /* The module context is optional */
1142 module_context =
1143 modulemd_obsoletes_get_module_context (MODULEMD_OBSOLETES (self));
1144 if (module_context)
1145 {
1146 if (!mmd_emitter_scalar (
1147 emitter, "context", YAML_PLAIN_SCALAR_STYLE, error))
1148 {
1149 return FALSE;
1150 }
1151
1152 if (!mmd_emitter_scalar (
1153 emitter, module_context, YAML_PLAIN_SCALAR_STYLE, error))
1154 {
1155 return FALSE;
1156 }
1157 }
1158
1159 /* The eol_date field is optional */
1160 eol_date = modulemd_obsoletes_get_eol_date (MODULEMD_OBSOLETES (self));
1161 if (eol_date)
1162 {
1163 eol_date_string = modulemd_guint64_to_iso8601date (eol_date);
1164 if (eol_date_string == NULL)
1165 {
1166 g_set_error (error,
1167 MODULEMD_ERROR,
1168 MMD_ERROR_VALIDATE,
1169 "Cannot convert eol_date: %" PRIu64 " to iso8601 date.",
1170 eol_date);
1171 return FALSE;
1172 }
1173 EMIT_KEY_VALUE (emitter, error, "eol_date", eol_date_string);
1174 }
1175
1176 /* The message is mandatory */
1177 if (!mmd_emitter_scalar (emitter, "message", YAML_PLAIN_SCALAR_STYLE, error))
1178 {
1179 return FALSE;
1180 }
1181
1182 if (!mmd_emitter_scalar (
1183 emitter,
1184 modulemd_obsoletes_get_message (MODULEMD_OBSOLETES (self)),
1185 YAML_PLAIN_SCALAR_STYLE,
1186 error))
1187 {
1188 return FALSE;
1189 }
1190
1191 /* Obsoleted_by are optional */
1192 if (modulemd_obsoletes_get_obsoleted_by_module_name (
1193 MODULEMD_OBSOLETES (self)) &&
1194 modulemd_obsoletes_get_obsoleted_by_module_stream (
1195 MODULEMD_OBSOLETES (self)))
1196 {
1197 if (!modulemd_obsoletes_emit_obsoleted_by (self, emitter, error))
1198 {
1199 return FALSE;
1200 }
1201 }
1202
1203 /* Close the data: section mapping */
1204 if (!mmd_emitter_end_mapping (emitter, error))
1205 {
1206 return FALSE;
1207 }
1208
1209 /* Close the top-level section mapping */
1210 if (!mmd_emitter_end_mapping (emitter, error))
1211 {
1212 return FALSE;
1213 }
1214
1215 /* End the document */
1216 if (!mmd_emitter_end_document (emitter, error))
1217 {
1218 return FALSE;
1219 }
1220
1221 return TRUE;
1222 }
1223
1224 gboolean
modulemd_obsoletes_is_active(ModulemdObsoletes * self)1225 modulemd_obsoletes_is_active (ModulemdObsoletes *self)
1226 {
1227 time_t rawtime;
1228 struct tm *tm;
1229 time (&rawtime);
1230 tm = gmtime (&rawtime);
1231
1232 char buf[255];
1233 strftime (buf, sizeof (buf), "%Y%m%d%H%M", tm);
1234 guint64 now = g_ascii_strtoull (buf, NULL, 0);
1235
1236 if (now >= modulemd_obsoletes_get_eol_date (self))
1237 {
1238 return TRUE;
1239 }
1240
1241 return FALSE;
1242 }
1243