@@ -60,6 +60,11 @@ modulemd_prioritizer_class_init (ModulemdPrioritizerClass *klass)
6060 object_class -> set_property = NULL ;
6161}
6262
63+ static GPtrArray *
64+ _deduplicate_module_streams (const GPtrArray * first ,
65+ const GPtrArray * second ,
66+ GError * * error );
67+
6368static void
6469_modulemd_ptr_array_unref (gpointer ptr )
6570{
@@ -82,7 +87,10 @@ modulemd_prioritizer_add (ModulemdPrioritizer *self,
8287{
8388 GPtrArray * current_objects = NULL ;
8489 g_autoptr (GPtrArray ) concat_objects = NULL ;
90+ g_autoptr (GPtrArray ) deduped_objects = NULL ;
8591 g_autoptr (GPtrArray ) merged_objects = NULL ;
92+ g_autoptr (ModulemdSimpleSet ) nsvcs = modulemd_simpleset_new ();
93+ g_autofree gchar * nsvc = NULL ;
8694 gint64 * prio = NULL ;
8795 gsize i ;
8896
@@ -142,14 +150,17 @@ modulemd_prioritizer_add (ModulemdPrioritizer *self,
142150 }
143151 }
144152
145- for (i = 0 ; i < objects -> len ; i ++ )
153+ deduped_objects =
154+ _deduplicate_module_streams (concat_objects , objects , error );
155+ if (!deduped_objects )
146156 {
147- g_ptr_array_add (concat_objects ,
148- g_object_ref (g_ptr_array_index (objects , i )));
157+ /* Something went wrong. Return the error here. */
158+ g_clear_pointer (& prio , g_free );
159+ return FALSE;
149160 }
150161
151162 merged_objects =
152- modulemd_merge_defaults (concat_objects , NULL , FALSE, error );
163+ modulemd_merge_defaults (deduped_objects , NULL , FALSE, error );
153164 if (!merged_objects )
154165 {
155166 /* Something went wrong. Return the error here. */
@@ -188,18 +199,18 @@ GPtrArray *
188199modulemd_prioritizer_resolve (ModulemdPrioritizer * self , GError * * error )
189200{
190201 g_autoptr (GPtrArray ) current = NULL ;
191- g_autoptr (GPtrArray ) next = NULL ;
202+ g_autoptr (GPtrArray ) prev = NULL ;
192203 g_autoptr (GPtrArray ) tmp = NULL ;
204+ g_autoptr (GPtrArray ) deduped_objects = NULL ;
193205 g_autoptr (GList ) priority_levels = NULL ;
194206 GList * current_level = NULL ;
195207
196208 g_return_val_if_fail (MODULEMD_IS_PRIORITIZER (self ), FALSE);
197209 g_return_val_if_fail (error == NULL || * error == NULL , FALSE);
198210
199- current_level = priority_levels =
200- _modulemd_ordered_int64_keys (self -> priorities );
211+ priority_levels = _modulemd_ordered_int64_keys (self -> priorities );
201212
202- if (!current_level )
213+ if (!priority_levels )
203214 {
204215 /* Nothing has been added to the resolver. */
205216 g_set_error (error ,
@@ -210,32 +221,144 @@ modulemd_prioritizer_resolve (ModulemdPrioritizer *self, GError **error)
210221 return NULL ;
211222 }
212223
224+ /* Go through the merge from highest priority down to lowest. */
225+ current_level = g_list_last (priority_levels );
226+
213227 current = g_ptr_array_ref (
214- g_hash_table_lookup (self -> priorities , priority_levels -> data ));
228+ g_hash_table_lookup (self -> priorities , current_level -> data ));
215229
216- while (current_level -> next )
230+ while (current_level -> prev )
217231 {
218- next = g_ptr_array_ref (
219- g_hash_table_lookup (self -> priorities , current_level -> next -> data ));
232+ prev = g_ptr_array_ref (
233+ g_hash_table_lookup (self -> priorities , current_level -> prev -> data ));
220234
221235 /* Merge the values, replacing any conflicts */
222- tmp = modulemd_merge_defaults (current , next , TRUE, error );
236+ tmp = modulemd_merge_defaults (prev , current , TRUE, error );
223237 if (!tmp )
224238 {
225239 /* Something went wrong with the merge. Return the error */
226240 return NULL ;
227241 }
242+
243+ /* Deduplicate after the merge */
244+ deduped_objects = _deduplicate_module_streams (tmp , NULL , error );
245+ if (!deduped_objects )
246+ {
247+ /* Something went wrong. Return the error here. */
248+ return NULL ;
249+ }
250+
228251 g_clear_pointer (& current , g_ptr_array_unref );
229- current = g_ptr_array_ref (tmp );
252+ current = g_ptr_array_ref (deduped_objects );
230253 g_clear_pointer (& tmp , g_ptr_array_unref );
231- g_clear_pointer (& next , g_ptr_array_unref );
254+ g_clear_pointer (& deduped_objects , g_ptr_array_unref );
255+ g_clear_pointer (& prev , g_ptr_array_unref );
232256
233- current_level = current_level -> next ;
257+ current_level = current_level -> prev ;
234258 }
235259
236260 return g_ptr_array_ref (current );
237261}
238262
263+ static GPtrArray *
264+ _deduplicate_module_streams (const GPtrArray * first ,
265+ const GPtrArray * second ,
266+ GError * * error )
267+ {
268+ GObject * object = NULL ;
269+ g_autoptr (GPtrArray ) deduplicated = NULL ;
270+ g_autoptr (ModulemdSimpleSet ) nsvcs = modulemd_simpleset_new ();
271+ g_autofree gchar * nsvc = NULL ;
272+ gssize reserved_size , i ;
273+
274+ g_return_val_if_fail (first , NULL );
275+ g_return_val_if_fail (error == NULL || * error == NULL , NULL );
276+
277+ /* Assume the common case that there are no duplicates and preallocate
278+ * space to hold the entire set.
279+ */
280+ reserved_size = first -> len ;
281+ if (second )
282+ {
283+ reserved_size += second -> len ;
284+ }
285+
286+ deduplicated = g_ptr_array_new_full (reserved_size , g_object_unref );
287+
288+ /* We check the second list here as a preventative measure. In a proper
289+ * implementation of this, we'd do a full check of the module stream entries
290+ * to ensure that they don't have the same NSVC but different content. For
291+ * now, however, we'll just assume that the second list has the right data
292+ * since it's likely to be newer.
293+ */
294+ if (second )
295+ for (i = 0 ; i < second -> len ; i ++ )
296+ {
297+ object = g_ptr_array_index (second , i );
298+
299+ if (MODULEMD_IS_MODULE (object ))
300+ {
301+ nsvc = modulemd_module_dup_nsvc (MODULEMD_MODULE (object ));
302+ }
303+ else if (MODULEMD_IS_MODULESTREAM (object ))
304+ {
305+ nsvc =
306+ modulemd_modulestream_get_nsvc (MODULEMD_MODULESTREAM (object ));
307+ }
308+ if (nsvc )
309+ {
310+ if (modulemd_simpleset_contains (nsvcs , nsvc ))
311+ {
312+ /* We've seen this NSVC before; skip it */
313+ continue ;
314+ }
315+
316+ /* Save this NSVC so we don't add it twice */
317+ modulemd_simpleset_add (nsvcs , nsvc );
318+ g_clear_pointer (& nsvc , g_free );
319+ }
320+
321+ g_ptr_array_add (deduplicated , g_object_ref (object ));
322+ }
323+
324+ /* For the 'first' list, go through in reverse order, because this may be
325+ * called after the modulemd_merge_defaults() routine has already
326+ * concatenated the higher-priority list. This will ensure that the
327+ * other list wins any merge disputes.
328+ */
329+ for (i = (gsize )first -> len - 1 ; i >= 0 ; i -- )
330+ {
331+ object = g_ptr_array_index (first , i );
332+
333+ if (MODULEMD_IS_MODULE (object ))
334+ {
335+ nsvc = modulemd_module_dup_nsvc (MODULEMD_MODULE (object ));
336+ }
337+ else if (MODULEMD_IS_MODULESTREAM (object ))
338+ {
339+ nsvc =
340+ modulemd_modulestream_get_nsvc (MODULEMD_MODULESTREAM (object ));
341+ }
342+
343+ if (nsvc )
344+ {
345+ if (modulemd_simpleset_contains (nsvcs , nsvc ))
346+ {
347+ /* We've seen this NSVC before; skip it */
348+ continue ;
349+ }
350+
351+ /* Save this NSVC so we don't add it twice */
352+ modulemd_simpleset_add (nsvcs , nsvc );
353+ g_clear_pointer (& nsvc , g_free );
354+ }
355+
356+ g_ptr_array_add (deduplicated , g_object_ref (object ));
357+ }
358+
359+ return g_ptr_array_ref (deduplicated );
360+ }
361+
239362
240363GHashTable *
241364modulemd_prioritizer_resolve_index (ModulemdPrioritizer * self , GError * * error )
0 commit comments