import libmodulemd-2.8.2-1.el8

This commit is contained in:
CentOS Sources 2020-04-28 05:40:47 -04:00 committed by Andrew Lukoshko
parent f1c27fa518
commit d123d4c82c
11 changed files with 52 additions and 2113 deletions

3
.gitignore vendored
View File

@ -1 +1,2 @@
SOURCES/modulemd-2.5.0.tar.xz SOURCES/modulemd-1.8.16.tar.xz
SOURCES/modulemd-2.8.2.tar.xz

View File

@ -1 +1,2 @@
2b6c3443a36ec821fd289ae6605e9dea4c5dbcda SOURCES/modulemd-2.5.0.tar.xz 6e55eddb35afc4cd28b6d8cb248f821af5f49dd7 SOURCES/modulemd-1.8.16.tar.xz
9846728616cff38995764e9b4315889ecb3d4637 SOURCES/modulemd-2.8.2.tar.xz

View File

@ -1,27 +0,0 @@
From 1a7bf143761ff8e3f4f6585b82c0be4dbd511fca Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Thu, 23 May 2019 14:00:36 -0400
Subject: [PATCH 1/8] Double valgrind timeout
On some architectures under heavy load, the valgrind check on v2
is taking a long time.
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
---
modulemd/meson.build | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/modulemd/meson.build b/modulemd/meson.build
index 47bd1f58e6401d2634d8ff737c2b347f5ebc6bf5..e49c7a9df76dcf37a18ddeba3150d6c914aa4e25 100644
--- a/modulemd/meson.build
+++ b/modulemd/meson.build
@@ -315,5 +315,5 @@ if valgrind.found()
test ('valgrind', python3,
env : test_env,
args : modulemd_valgrind_scripts,
- timeout : 600)
+ timeout : 1200)
endif
--
2.23.0

View File

@ -1,125 +0,0 @@
From d9b41f72d4b2d545b2600aff7bd8a27ed0093750 Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Wed, 29 May 2019 11:33:57 -0400
Subject: [PATCH 2/8] Parallelize the valgrind tests
This considerably reduces the time needed to perform the valgrind
memory tests on systems with multiple available processors. In the
case of my laptop, the duration was reduced from ~200s to 90s.
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
---
modulemd/common/tests/test-valgrind.py | 74 ++++++++++++++------------
1 file changed, 41 insertions(+), 33 deletions(-)
diff --git a/modulemd/common/tests/test-valgrind.py b/modulemd/common/tests/test-valgrind.py
index 9be72c705fde79aa305d831eaa4f31f7e2cc663f..9349749658ccca0529776f3d534664d614c1cb4d 100644
--- a/modulemd/common/tests/test-valgrind.py
+++ b/modulemd/common/tests/test-valgrind.py
@@ -18,9 +18,12 @@ import subprocess
import tempfile
import xml.etree.ElementTree as ET
+from multiprocessing import Pool, TimeoutError
+
if os.getenv('MMD_SKIP_VALGRIND'):
sys.exit(77)
+
failed = False
# Get the list of tests to run
@@ -49,9 +52,9 @@ for test in unfiltered_tests:
continue
tests.append(test)
+
with tempfile.TemporaryDirectory(prefix="libmodulemd_valgrind_") as tmpdirname:
- for test in tests:
- # TODO: auto-detect the location of the suppression file
+ def exec_valgrind(test):
valgrind_command = "/usr/bin/valgrind " \
"--leak-check=full " \
"--suppressions=/usr/share/glib-2.0/valgrind/glib.supp " \
@@ -66,42 +69,47 @@ with tempfile.TemporaryDirectory(prefix="libmodulemd_valgrind_") as tmpdirname:
'--wrap=%s' % valgrind_command,
test])
- if proc_result.returncode != 0:
- print("Valgrind exited with an error on %s" % test,
- file=sys.stderr)
- failed = True
- continue
+ return proc_result.returncode, test
- # Process the XML for leaks
- tree = ET.parse('%s/%s.xml' % (tmpdirname, test))
- root = tree.getroot()
+ with Pool() as pool:
+ for returncode, test in pool.map(exec_valgrind, tests):
+ if returncode != 0:
+ print("Valgrind exited with an error on %s" % test,
+ file=sys.stderr)
+ failed = True
+ continue
- for root_child in root:
- if (root_child.tag == "error"):
- for error_child in root_child:
- if error_child.tag == 'kind':
- if error_child.text == 'Leak_DefinitelyLost':
- print("Memory leak detected in %s" % test,
- file=sys.stderr)
- failed = True
+ # Process the XML for leaks
+ tree = ET.parse('%s/%s.xml' % (tmpdirname, test))
+ root = tree.getroot()
- elif error_child.text == 'InvalidFree':
- print("Invalid free() detected in %s" % test,
- file=sys.stderr)
- failed = True
+ for root_child in root:
+ if (root_child.tag == "error"):
+ for error_child in root_child:
+ if error_child.tag == 'kind':
+ if error_child.text == 'Leak_DefinitelyLost':
+ print("Memory leak detected in %s" % test,
+ file=sys.stderr)
+ failed = True
- elif error_child.text == 'InvalidRead':
- print("Invalid read detected in %s" % test,
- file=sys.stderr)
- failed = True
+ elif error_child.text == 'InvalidFree':
+ print("Invalid free() detected in %s" % test,
+ file=sys.stderr)
+ failed = True
- elif error_child.text == 'UninitCondition':
- print("Uninitialized usage detected in %s" % test,
- file=sys.stderr)
- failed = True
- if failed:
- with open('%s/%s.xml' % (tmpdirname, test), 'r') as xml:
- print(xml.read())
+ elif error_child.text == 'InvalidRead':
+ print("Invalid read detected in %s" % test,
+ file=sys.stderr)
+ failed = True
+
+ elif error_child.text == 'UninitCondition':
+ print(
+ "Uninitialized usage detected in %s" %
+ test, file=sys.stderr)
+ failed = True
+ if failed:
+ with open('%s/%s.xml' % (tmpdirname, test), 'r') as xml:
+ print(xml.read())
if failed:
--
2.23.0

View File

@ -1,136 +0,0 @@
From 340e316bd6384562086b4e381c8cd42b1ccd0781 Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Tue, 28 May 2019 14:28:30 -0400
Subject: [PATCH 3/8] Fix transfer type for Module.search_streams()
Technically this is an API-breaking change, but no one is using it
yet and it was always expected to be managed this way.
Fixes: https://github.com/fedora-modularity/libmodulemd/issues/308
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
---
modulemd/meson.build | 1 +
.../v2/include/modulemd-2.0/modulemd-module.h | 4 +-
modulemd/v2/meson.build | 17 ++++++-
modulemd/v2/tests/ModulemdTests/module.py | 46 +++++++++++++++++++
4 files changed, 65 insertions(+), 3 deletions(-)
create mode 100644 modulemd/v2/tests/ModulemdTests/module.py
diff --git a/modulemd/meson.build b/modulemd/meson.build
index e49c7a9df76dcf37a18ddeba3150d6c914aa4e25..e5912d4041ba3e427d13b98c0eeca5217d48244b 100644
--- a/modulemd/meson.build
+++ b/modulemd/meson.build
@@ -231,6 +231,7 @@ test_v2_python_scripts = files(
'v2/tests/ModulemdTests/defaultsv1.py',
'v2/tests/ModulemdTests/dependencies.py',
'v2/tests/ModulemdTests/merger.py',
+ 'v2/tests/ModulemdTests/module.py',
'v2/tests/ModulemdTests/moduleindex.py',
'v2/tests/ModulemdTests/modulestream.py',
'v2/tests/ModulemdTests/profile.py',
diff --git a/modulemd/v2/include/modulemd-2.0/modulemd-module.h b/modulemd/v2/include/modulemd-2.0/modulemd-module.h
index 45be9c0ae96e203707da61d84f18c71c4a826035..0219cfe227652813d20bdf736f9033782084c5ad 100644
--- a/modulemd/v2/include/modulemd-2.0/modulemd-module.h
+++ b/modulemd/v2/include/modulemd-2.0/modulemd-module.h
@@ -131,8 +131,8 @@ modulemd_module_get_stream_by_NSVC (ModulemdModule *self,
* @arch: (nullable): The processor architecture of the stream to retrieve. If
* NULL, the architecture is not included in the search.
*
- * Returns: (transfer full) (element-type ModulemdModuleStream): The list of
- * stream objects matching the requested parameters. This function cannot
+ * Returns: (transfer container) (element-type ModulemdModuleStream): The list
+ * of stream objects matching the requested parameters. This function cannot
* fail, but it may return a zero-length list if no matches were found. The
* returned streams will be in a predictable order, sorted first by stream
* name, then by version (highest to lowest), then by context and finally by
diff --git a/modulemd/v2/meson.build b/modulemd/v2/meson.build
index 3f45db2c4e0e9a8996c74dffd949d5276082dc6f..e8a5a38f0528c4f860f0b84ef63609ff5fd89caa 100644
--- a/modulemd/v2/meson.build
+++ b/modulemd/v2/meson.build
@@ -392,6 +392,22 @@ test ('dependencies_python2_release', python2,
env : py_test_release_env,
args : dependencies_python_script)
+# -- Test Modulemd.Module (Python) -- #
+module_python_script = files('tests/ModulemdTests/module.py')
+test ('module_python3_debug', python3,
+ env : py_test_env,
+ args : module_python_script)
+test ('module_python3_release', python3,
+ env : py_test_release_env,
+ args : module_python_script)
+
+test ('module_python2_debug', python2,
+ env : py_test_env,
+ args : module_python_script)
+test ('module_python2_release', python2,
+ env : py_test_release_env,
+ args : module_python_script)
+
# -- Test Modulemd.ModuleIndex (Python) -- #
moduleindex_python_script = files('tests/ModulemdTests/moduleindex.py')
test ('moduleindex_python3_debug', python3,
@@ -401,7 +417,6 @@ test ('moduleindex_python3_release', python3,
env : py_test_release_env,
args : moduleindex_python_script)
-moduleindex_python_script = files('tests/ModulemdTests/moduleindex.py')
test ('moduleindex_python2_debug', python2,
env : py_test_env,
args : moduleindex_python_script)
diff --git a/modulemd/v2/tests/ModulemdTests/module.py b/modulemd/v2/tests/ModulemdTests/module.py
new file mode 100644
index 0000000000000000000000000000000000000000..b604d9c9b357c4a5211d3ba5b4d0aba08c3a42bd
--- /dev/null
+++ b/modulemd/v2/tests/ModulemdTests/module.py
@@ -0,0 +1,46 @@
+#!/usr/bin/python3
+
+# This file is part of libmodulemd
+# Copyright (C) 2017-2018 Stephen Gallagher
+#
+# Fedora-License-Identifier: MIT
+# SPDX-2.0-License-Identifier: MIT
+# SPDX-3.0-License-Identifier: MIT
+#
+# This program is free software.
+# For more information on the license, see COPYING.
+# For more information on free software, see
+# <https://www.gnu.org/philosophy/free-sw.en.html>.
+
+from os import path
+import sys
+try:
+ import unittest
+ import gi
+ gi.require_version('Modulemd', '2.0')
+ from gi.repository import Modulemd
+ from gi.repository.Modulemd import ModuleIndex
+ from gi.repository import GLib
+except ImportError:
+ # Return error 77 to skip this test on platforms without the necessary
+ # python modules
+ sys.exit(77)
+
+from base import TestBase
+
+
+class TestModule(TestBase):
+
+ def test_search_streams(self):
+ idx = Modulemd.ModuleIndex.new()
+ idx.update_from_file(path.join(self.source_root,
+ "modulemd/v2/tests/test_data/f29.yaml"),
+ True)
+ module = idx.get_module('nodejs')
+
+ self.assertEquals(len(module.search_streams('8', 0)), 1)
+ self.assertEquals(len(module.search_streams('10', 0)), 1)
+
+
+if __name__ == '__main__':
+ unittest.main()
--
2.23.0

View File

@ -1,27 +0,0 @@
From 82e56d78e46504aab5917b606eae67e1a3b54603 Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Wed, 29 May 2019 16:18:30 -0400
Subject: [PATCH 4/8] Extend timeout for header test
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
---
modulemd/meson.build | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/modulemd/meson.build b/modulemd/meson.build
index e5912d4041ba3e427d13b98c0eeca5217d48244b..0741736a12b4457559ade0a5372ff4b25743fce3 100644
--- a/modulemd/meson.build
+++ b/modulemd/meson.build
@@ -308,7 +308,8 @@ if build_api_v2
import_header_script = find_program('common/tests/test-import-headers.sh')
test ('test_v2_import_headers', import_header_script,
env : test_env,
- args : modulemd_v2_hdrs)
+ args : modulemd_v2_hdrs,
+ timeout : 300)
endif
if valgrind.found()
--
2.23.0

View File

@ -1,41 +0,0 @@
From b338dee563932c44bed50b54a1ce00c8e83c0465 Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Wed, 23 Oct 2019 11:13:55 -0400
Subject: [PATCH 5/8] Add test_data_path env var for Python tests
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
---
modulemd/v2/meson.build | 1 +
modulemd/v2/tests/ModulemdTests/base.py | 4 ++++
2 files changed, 5 insertions(+)
diff --git a/modulemd/v2/meson.build b/modulemd/v2/meson.build
index e8a5a38f0528c4f860f0b84ef63609ff5fd89caa..5137b7d23ec66e39a56cf022974da6570c8e4822 100644
--- a/modulemd/v2/meson.build
+++ b/modulemd/v2/meson.build
@@ -93,6 +93,7 @@ install_headers(
test_release_env = environment()
test_release_env.set('LC_ALL', 'C')
test_release_env.set ('MESON_SOURCE_ROOT', meson.source_root())
+test_release_env.set ('TEST_DATA_PATH', meson.source_root() + '/modulemd/tests/test_data')
# Test env with fatal warnings and criticals
test_env = test_release_env
diff --git a/modulemd/v2/tests/ModulemdTests/base.py b/modulemd/v2/tests/ModulemdTests/base.py
index 831309634100f25533c9a7dafe7f96bf7e100cd7..5f396958fd7a20e6567cfe69f99eaeb95825663a 100644
--- a/modulemd/v2/tests/ModulemdTests/base.py
+++ b/modulemd/v2/tests/ModulemdTests/base.py
@@ -28,6 +28,10 @@ class TestBase(unittest.TestCase):
def source_root(self):
return os.getenv("MESON_SOURCE_ROOT")
+ @property
+ def test_data_path(self):
+ return os.getenv("TEST_DATA_PATH")
+
def _catch_signal(self, *sigargs):
if self._caught_signal:
raise AssertionError("Multiple signals were caught")
--
2.23.0

View File

@ -1,272 +0,0 @@
From 200838c96b48cbe849af652cbb7ece98205cbf9d Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Wed, 3 Jul 2019 08:05:25 -0400
Subject: [PATCH 6/8] Add ModuleIndexMerger.resolve_ext()
This will allow us to handle default streams strictly when merging. In most end-user
cases, we want default stream conflicts to simply drop the default stream (this is
fail-safe). But when we are creating a repo with defaults, we want to be stricter and
ensure that we aren't producing a repo with inconsistent data.
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
---
.../modulemd-module-index-merger.h | 33 +++++++++++++++++++
.../private/modulemd-defaults-private.h | 3 ++
.../private/modulemd-defaults-v1-private.h | 1 +
.../private/modulemd-module-index-private.h | 4 +++
modulemd/v2/modulemd-defaults-v1.c | 12 +++++++
modulemd/v2/modulemd-defaults.c | 2 ++
modulemd/v2/modulemd-module-index-merger.c | 12 ++++++-
modulemd/v2/modulemd-module-index.c | 5 +--
modulemd/v2/tests/ModulemdTests/merger.py | 21 ++++++++++++
9 files changed, 90 insertions(+), 3 deletions(-)
diff --git a/modulemd/v2/include/modulemd-2.0/modulemd-module-index-merger.h b/modulemd/v2/include/modulemd-2.0/modulemd-module-index-merger.h
index b019f0ed856684a003e9c2f6abefc70e1448246a..97ca7ebb3824ef62aabbafee391b25d56bac43c3 100644
--- a/modulemd/v2/include/modulemd-2.0/modulemd-module-index-merger.h
+++ b/modulemd/v2/include/modulemd-2.0/modulemd-module-index-merger.h
@@ -161,6 +161,10 @@ modulemd_module_index_merger_associate_index (ModulemdModuleIndexMerger *self,
* #ModulemdModuleIndexMerger is undefined. The only valid action on it after
* that point is g_object_unref().
*
+ * This function is equivalent to calling
+ * modulemd_module_index_merger_resolve_ext() with
+ * `strict_default_streams=FALSE`.
+ *
* Returns: (transfer full): A newly-allocated #ModulemdModuleIndex containing
* the merged results. If this function encounters an unresolvable merge
* conflict, it will return NULL and set @error appropriately.
@@ -171,4 +175,33 @@ ModulemdModuleIndex *
modulemd_module_index_merger_resolve (ModulemdModuleIndexMerger *self,
GError **error);
+
+/**
+ * modulemd_module_index_merger_resolve_ext:
+ * @self: (in): This #ModulemdModuleIndexMerger object.
+ * @strict_default_streams: (in): If TRUE, merging two #ModulemdDefaults with
+ * conflicting default streams will raise an error. If FALSE, the module will
+ * have its default stream blocked.
+ * @error: (out): A #GError containing the reason for a failure to resolve the
+ * merges.
+ *
+ * Merges all added #ModulemdModuleIndex objects according to their priority.
+ * The logic of this merge is described in the Description of
+ * #ModulemdModuleIndexMerger.
+ *
+ * Once this function has been called, the internal state of the
+ * #ModulemdModuleIndexMerger is undefined. The only valid action on it after
+ * that point is g_object_unref().
+ *
+ * Returns: (transfer full): A newly-allocated #ModulemdModuleIndex containing
+ * the merged results. If this function encounters an unresolvable merge
+ * conflict, it will return NULL and set @error appropriately.
+ *
+ * Since: 2.6
+ */
+ModulemdModuleIndex *
+modulemd_module_index_merger_resolve_ext (ModulemdModuleIndexMerger *self,
+ gboolean strict_default_streams,
+ GError **error);
+
G_END_DECLS
diff --git a/modulemd/v2/include/private/modulemd-defaults-private.h b/modulemd/v2/include/private/modulemd-defaults-private.h
index 1863cf6365e769b184478ba5435c664ac05a0b2f..6ea3a54ff992890e88badfdaefa1483b9ba52429 100644
--- a/modulemd/v2/include/private/modulemd-defaults-private.h
+++ b/modulemd/v2/include/private/modulemd-defaults-private.h
@@ -38,6 +38,8 @@ modulemd_defaults_set_module_name (ModulemdDefaults *self,
* modulemd_defaults_merge:
* @from: (in): A #ModulemdDefaults object to merge from
* @into: (in): A #ModulemdDefaults object being merged into
+ * @strict_default_streams: (in): Whether a stream conflict should throw an
+ * error or just unset the default stream.
* @error: (out): A #GError containing the reason for an unresolvable merge
* conflict
*
@@ -52,6 +54,7 @@ modulemd_defaults_set_module_name (ModulemdDefaults *self,
ModulemdDefaults *
modulemd_defaults_merge (ModulemdDefaults *from,
ModulemdDefaults *into,
+ gboolean strict_default_streams,
GError **error);
G_END_DECLS
diff --git a/modulemd/v2/include/private/modulemd-defaults-v1-private.h b/modulemd/v2/include/private/modulemd-defaults-v1-private.h
index de2ede98e6fb49bfd792b5f2913868fad6ff27db..9144a7ef90853a28eee8345a3b814fdc6478be7b 100644
--- a/modulemd/v2/include/private/modulemd-defaults-v1-private.h
+++ b/modulemd/v2/include/private/modulemd-defaults-v1-private.h
@@ -74,6 +74,7 @@ ModulemdDefaults *
modulemd_defaults_v1_merge (const gchar *module_name,
ModulemdDefaultsV1 *from,
ModulemdDefaultsV1 *into,
+ gboolean strict_default_streams,
GError **error);
G_END_DECLS
diff --git a/modulemd/v2/include/private/modulemd-module-index-private.h b/modulemd/v2/include/private/modulemd-module-index-private.h
index fd37ab30dffa99f81b2762cb4e23546fe990b2f6..62fc71844f3a58030f79e7da628656b3ffcba5ae 100644
--- a/modulemd/v2/include/private/modulemd-module-index-private.h
+++ b/modulemd/v2/include/private/modulemd-module-index-private.h
@@ -72,6 +72,9 @@ modulemd_module_index_update_from_parser (ModulemdModuleIndex *self,
* argument specifies whether the contents of @from will supersede those from
* @into. For specifics of how this works, see the Description section for
* #ModulemdIndexMerger.
+ * @strict_default_streams: (in): When merging #ModulemdDefaults, treat
+ * conflicting stream defaults as an error if this is True. Otherwise, on a
+ * conflict, the default stream will be unset.
* @error: (out): If the merge fails, this will return a #GError explaining the
* reason for it.
*
@@ -84,6 +87,7 @@ gboolean
modulemd_module_index_merge (ModulemdModuleIndex *from,
ModulemdModuleIndex *into,
gboolean override,
+ gboolean strict_default_streams,
GError **error);
G_END_DECLS
diff --git a/modulemd/v2/modulemd-defaults-v1.c b/modulemd/v2/modulemd-defaults-v1.c
index 55f899b530ef59e0d60de982db76440c7a493325..f51e79d9b0a9fb0395077cd1c3be16529dd53f92 100644
--- a/modulemd/v2/modulemd-defaults-v1.c
+++ b/modulemd/v2/modulemd-defaults-v1.c
@@ -1204,6 +1204,7 @@ ModulemdDefaults *
modulemd_defaults_v1_merge (const gchar *module_name,
ModulemdDefaultsV1 *from,
ModulemdDefaultsV1 *into,
+ gboolean strict_default_streams,
GError **error)
{
g_autoptr (ModulemdDefaultsV1) merged = NULL;
@@ -1246,6 +1247,17 @@ modulemd_defaults_v1_merge (const gchar *module_name,
g_info ("Module stream mismatch in merge: %s != %s",
into->default_stream,
from->default_stream);
+ if (strict_default_streams)
+ {
+ g_set_error (error,
+ MODULEMD_ERROR,
+ MODULEMD_ERROR_VALIDATE,
+ "Default stream mismatch in module %s: %s != %s",
+ module_name,
+ into->default_stream,
+ from->default_stream);
+ return NULL;
+ }
modulemd_defaults_v1_set_default_stream (
merged, DEFAULT_MERGE_CONFLICT, NULL);
}
diff --git a/modulemd/v2/modulemd-defaults.c b/modulemd/v2/modulemd-defaults.c
index 9711fbdbd267570d01d8df4962a2c4e2a7d25c6e..2157f21fd4079ee096baee2a3a3552df5c273d06 100644
--- a/modulemd/v2/modulemd-defaults.c
+++ b/modulemd/v2/modulemd-defaults.c
@@ -391,6 +391,7 @@ modulemd_defaults_init (ModulemdDefaults *self)
ModulemdDefaults *
modulemd_defaults_merge (ModulemdDefaults *from,
ModulemdDefaults *into,
+ gboolean strict_default_streams,
GError **error)
{
g_autoptr (ModulemdDefaults) merged_defaults = NULL;
@@ -446,6 +447,7 @@ modulemd_defaults_merge (ModulemdDefaults *from,
merged_defaults = modulemd_defaults_v1_merge (module_name,
MODULEMD_DEFAULTS_V1 (from),
MODULEMD_DEFAULTS_V1 (into),
+ strict_default_streams,
&nested_error);
if (!merged_defaults)
{
diff --git a/modulemd/v2/modulemd-module-index-merger.c b/modulemd/v2/modulemd-module-index-merger.c
index b8abda8eef91d88538d617b2e15fc77970110ba6..c3502f5c95f7b3227ed772db302d1cc67ca16c7c 100644
--- a/modulemd/v2/modulemd-module-index-merger.c
+++ b/modulemd/v2/modulemd-module-index-merger.c
@@ -170,6 +170,14 @@ modulemd_module_index_merger_associate_index (ModulemdModuleIndexMerger *self,
ModulemdModuleIndex *
modulemd_module_index_merger_resolve (ModulemdModuleIndexMerger *self,
GError **error)
+{
+ return modulemd_module_index_merger_resolve_ext (self, FALSE, error);
+}
+
+ModulemdModuleIndex *
+modulemd_module_index_merger_resolve_ext (ModulemdModuleIndexMerger *self,
+ gboolean strict_default_streams,
+ GError **error)
{
MODULEMD_INIT_TRACE ();
g_autoptr (ModulemdModuleIndex) thislevel = NULL;
@@ -200,6 +208,7 @@ modulemd_module_index_merger_resolve (ModulemdModuleIndexMerger *self,
if (!modulemd_module_index_merge (g_ptr_array_index (indexes, j),
thislevel,
FALSE,
+ strict_default_streams,
&nested_error))
{
g_propagate_error (error, g_steal_pointer (&nested_error));
@@ -209,7 +218,8 @@ modulemd_module_index_merger_resolve (ModulemdModuleIndexMerger *self,
/* Merge 'thislevel' into 'final' with override=True */
- if (!modulemd_module_index_merge (thislevel, final, TRUE, &nested_error))
+ if (!modulemd_module_index_merge (
+ thislevel, final, TRUE, strict_default_streams, &nested_error))
{
g_propagate_error (error, g_steal_pointer (&nested_error));
return NULL;
diff --git a/modulemd/v2/modulemd-module-index.c b/modulemd/v2/modulemd-module-index.c
index e67f91ec9ba7e0b629f871c85024fd76b6ef3c4d..61878d5b1cbf060b11729328c38027a7ba526b42 100644
--- a/modulemd/v2/modulemd-module-index.c
+++ b/modulemd/v2/modulemd-module-index.c
@@ -908,6 +908,7 @@ gboolean
modulemd_module_index_merge (ModulemdModuleIndex *from,
ModulemdModuleIndex *into,
gboolean override,
+ gboolean strict_default_streams,
GError **error)
{
MODULEMD_INIT_TRACE ();
@@ -996,8 +997,8 @@ modulemd_module_index_merge (ModulemdModuleIndex *from,
}
else
{
- merged_defaults =
- modulemd_defaults_merge (defaults, into_defaults, &nested_error);
+ merged_defaults = modulemd_defaults_merge (
+ defaults, into_defaults, strict_default_streams, &nested_error);
if (!merged_defaults)
{
g_propagate_error (error, g_steal_pointer (&nested_error));
diff --git a/modulemd/v2/tests/ModulemdTests/merger.py b/modulemd/v2/tests/ModulemdTests/merger.py
index b87c05798af98d93dfcf67c8b0be629dd94efe4f..92c90d185f55b8a7d5f856aa16cdce5ff32f30d8 100644
--- a/modulemd/v2/tests/ModulemdTests/merger.py
+++ b/modulemd/v2/tests/ModulemdTests/merger.py
@@ -210,6 +210,27 @@ class TestModuleIndexMerger(TestBase):
def test_merger_with_modified(self):
pass
+ def test_strict_default_streams(self):
+ merger = Modulemd.ModuleIndexMerger.new()
+
+ for stream in ("27", "38"):
+ default = """
+---
+document: modulemd-defaults
+version: 1
+data:
+ module: python
+ stream: %s
+...
+""" % (stream)
+
+ index = Modulemd.ModuleIndex()
+ index.update_from_string(default, strict=True)
+ merger.associate_index(index, 0)
+
+ with self.assertRaisesRegexp(gi.repository.GLib.GError, "Default stream mismatch in module python"):
+ merger.resolve_ext(True)
+
if __name__ == '__main__':
unittest.main()
--
2.23.0

View File

@ -1,949 +0,0 @@
From de49d4386cf3c842ce63d2005a624bdfc369c247 Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Fri, 27 Sep 2019 15:21:27 -0400
Subject: [PATCH 7/8] Rework defaults merging logic
Updates documentation of ModuleIndexMerger with the new algorithm.
Also fixes a memory leak in DefaultsV1.set_default_stream()
Fixes: https://github.com/fedora-modularity/libmodulemd/issues/368
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
---
.../merger/add_conflicting_profile.yaml | 7 +
.../merger/add_conflicting_stream.yaml | 9 +
...nflicting_stream_and_profile_modified.yaml | 11 +
modulemd/tests/test_data/merger/add_only.yaml | 8 +
modulemd/tests/test_data/merger/base.yaml | 34 +++
.../modulemd-module-index-merger.h | 67 +++---
.../private/modulemd-defaults-v1-private.h | 23 +-
modulemd/v2/modulemd-defaults-v1.c | 207 ++++++++++--------
modulemd/v2/modulemd-defaults.c | 28 +--
modulemd/v2/tests/ModulemdTests/merger.py | 119 ++++++++++
modulemd/v2/tests/test-modulemd-merger.c | 147 +++++++++++++
11 files changed, 510 insertions(+), 150 deletions(-)
create mode 100644 modulemd/tests/test_data/merger/add_conflicting_profile.yaml
create mode 100644 modulemd/tests/test_data/merger/add_conflicting_stream.yaml
create mode 100644 modulemd/tests/test_data/merger/add_conflicting_stream_and_profile_modified.yaml
create mode 100644 modulemd/tests/test_data/merger/add_only.yaml
create mode 100644 modulemd/tests/test_data/merger/base.yaml
diff --git a/modulemd/tests/test_data/merger/add_conflicting_profile.yaml b/modulemd/tests/test_data/merger/add_conflicting_profile.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..29b0dd0d41f61b8e83f6adde3334ee1a1f65893a
--- /dev/null
+++ b/modulemd/tests/test_data/merger/add_conflicting_profile.yaml
@@ -0,0 +1,7 @@
+document: modulemd-defaults
+version: 1
+data:
+ module: postgresql
+ stream: '8.1'
+ profiles:
+ '8.1': [client, server]
diff --git a/modulemd/tests/test_data/merger/add_conflicting_stream.yaml b/modulemd/tests/test_data/merger/add_conflicting_stream.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..615ca8746f8c880f220bdb01275c1ef37104185d
--- /dev/null
+++ b/modulemd/tests/test_data/merger/add_conflicting_stream.yaml
@@ -0,0 +1,9 @@
+---
+document: modulemd-defaults
+version: 1
+data:
+ module: postgresql
+ stream: '8.2'
+ profiles:
+ '8.2': [client, server, foo]
+
diff --git a/modulemd/tests/test_data/merger/add_conflicting_stream_and_profile_modified.yaml b/modulemd/tests/test_data/merger/add_conflicting_stream_and_profile_modified.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..db4bf38515502316d667a48d41a64a9f4a2937c3
--- /dev/null
+++ b/modulemd/tests/test_data/merger/add_conflicting_stream_and_profile_modified.yaml
@@ -0,0 +1,11 @@
+---
+document: modulemd-defaults
+version: 1
+data:
+ module: postgresql
+ stream: '8.2'
+ modified: 201909270000
+ profiles:
+ '8.1': [client, server]
+ '8.2': [client, server, foo]
+
diff --git a/modulemd/tests/test_data/merger/add_only.yaml b/modulemd/tests/test_data/merger/add_only.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..4a717807f928435ada8f3cf6fcdbd4c86927062e
--- /dev/null
+++ b/modulemd/tests/test_data/merger/add_only.yaml
@@ -0,0 +1,8 @@
+---
+document: modulemd-defaults
+version: 1
+data:
+ module: httpd
+ stream: 2.8
+ profiles:
+ '2.10': [notreal]
diff --git a/modulemd/tests/test_data/merger/base.yaml b/modulemd/tests/test_data/merger/base.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..12fbc7142040e4edbcba34b17a1dff341beaf1a4
--- /dev/null
+++ b/modulemd/tests/test_data/merger/base.yaml
@@ -0,0 +1,34 @@
+---
+# Intents optional:
+document: modulemd-defaults
+version: 1
+data:
+ module: httpd
+ profiles:
+ '2.2': [client, server]
+ '2.8': [notreal]
+ intents:
+ workstation:
+ stream: '2.4'
+ profiles:
+ '2.4': [client]
+ '2.6': [client, server, bindings]
+---
+document: modulemd-defaults
+version: 1
+data:
+ module: postgresql
+ stream: '8.1'
+ profiles:
+ '8.1': [client, server, foo]
+ '8.3': [client, server]
+---
+document: modulemd-defaults
+version: 1
+data:
+ module: nodejs
+ stream: '8.0'
+ modified: 201909270000
+ profiles:
+ '6.0': [default]
+ '8.0': [super]
diff --git a/modulemd/v2/include/modulemd-2.0/modulemd-module-index-merger.h b/modulemd/v2/include/modulemd-2.0/modulemd-module-index-merger.h
index 97ca7ebb3824ef62aabbafee391b25d56bac43c3..ad7c02ca5ec236d75e9d3ad51af8e2f6afab54c4 100644
--- a/modulemd/v2/include/modulemd-2.0/modulemd-module-index-merger.h
+++ b/modulemd/v2/include/modulemd-2.0/modulemd-module-index-merger.h
@@ -51,35 +51,48 @@ G_BEGIN_DECLS
* there exists two #ModulemdModuleStream entries that have different content
* for the same NSVC, the behavior is undefined.
*
- * Merging #ModulemdDefaults entries behaves as follows:
+ * Merging #ModulemdDefaults entries behaves as follows (note that this
+ * behavior has changed slightly as of 2.8.1):
*
- * - Within a ModuleIndex, if two or more default entries reference the same
- * module, the one with the highest modified field will be used and the
- * others discarded.
- * - When merging ModuleIndexes, if two or more indexes contain Defaults for
- * the same module, but different modified values, the one with the highest
- * modified value will be used and the others discarded.
- * - Any module default that is provided by a single repository is
- * authoritative.
- * - If the repos have different priorities (not common), then the default for
- * this module and stream name coming from the repo of higher priority will
- * be used and the default from the lower-priority repo will not be included
- * even if it has a higher modified value.
+ * - Any module defaults object that is provided by a single
+ * #ModulemdModuleIndex will be the defaults object in the resulting merged
+ * #ModulemdModuleIndex.
+ * - If the #ModulemdModuleIndex inputs have different priorities (not common),
+ * then the defaults from the highest priority #ModulemdModuleIndex will be
+ * used and the others entirely discarded. The `modified` value will not be
+ * considered at all. (Priority is intended for providing a total override,
+ * including an on-disk configuration).
* - If the repos have the same priority (such as "fedora" and "updates" in the
- * Fedora Project) and modified value, the entries will be merged as follows:
- * - If both repositories specify the same default stream for the module, use
- * it.
- * - If either repository specifies a default stream for the module and the
- * other does not, use the one specified.
- * - If both repositories specify different default streams, the merge will
- * unset the default stream and proceed with the merge.
- * - If both repositories specify a set of default profiles for a stream and
- * the sets are equivalent, use that set.
- * - If one repository specifies a set of default profiles for a stream and
- * the other does not, use the one specified.
- * - If both repositories specify a set of default profiles for a stream and
- * each are providing a different set, this is an unresolvable merge
- * conflict and the merge resolution will fail and report an error.
+ * Fedora Project) and `modified` value, the entries will be merged as
+ * follows for default streams:
+ * - If both #ModulemdModuleIndex objects specify the same default stream for
+ * the module, that one will be used.
+ * - If either #ModulemdModuleIndex specifies a default stream for the module
+ * and the other does not, the provided one will be used.
+ * - If both #ModulemdModuleIndex objects specify different default streams
+ * and have different `modified` values, the default stream from the
+ * #ModulemdDefaults object with the higher `modified` value will be used.
+ * - If both #ModulemdModuleIndex objects specify different default streams
+ * and have the same `modified` value, the merge will unset the default
+ * stream and leave no default stream in the resulting merged
+ * #ModulemdModuleIndex. This behavior can be controlled by using
+ * modulemd_module_index_merger_resolve_ext() and setting
+ * `strict_default_streams` to #TRUE. In that case, an error will be
+ * returned if conflicting default streams have been provided.
+ * - and for profile defaults:
+ * - If both #ModulemdModuleIndex objects specify a set of default profiles
+ * for a particular module and stream and the sets are equivalent, use that
+ * set.
+ * - If one #ModulemdModuleIndex object specifies a set of default profiles
+ * for a module and stream and the other does not, use the provided set.
+ * - If both #ModulemdModuleIndex objects specify a set of default profiles
+ * for a stream, each are providing a different set and the `modified`
+ * value differs, the set from the object with the higher `modified` value
+ * will be used.
+ * - If both #ModulemdModuleIndex objects specify a set of default profiles
+ * for a stream, each are providing a different set and the `modified`
+ * value is the same, this is an unresolvable merge conflict and the merge
+ * resolution will fail and return an error.
* - Intents behave in exactly the same manner as described for the top-level
* defaults, except that they merge beneath each intent name.
*
diff --git a/modulemd/v2/include/private/modulemd-defaults-v1-private.h b/modulemd/v2/include/private/modulemd-defaults-v1-private.h
index 9144a7ef90853a28eee8345a3b814fdc6478be7b..437bab1afa8c50c4a13924c8bc825ddb0bb211d4 100644
--- a/modulemd/v2/include/private/modulemd-defaults-v1-private.h
+++ b/modulemd/v2/include/private/modulemd-defaults-v1-private.h
@@ -70,9 +70,28 @@ modulemd_defaults_v1_emit_yaml (ModulemdDefaultsV1 *self,
GError **error);
+/**
+ * modulemd_defaults_v1_merge:
+ * @from: (in): A #ModulemdDefaultsV1 object to merge from.
+ * @into: (in): A #ModulemdDefaultsV1 object being merged into.
+ * @strict_default_streams: (in): Whether a stream conflict should throw an
+ * error or just unset the default stream.
+ * @error: (out): A #GError containing the reason for an unresolvable merge
+ * conflict.
+ *
+ * Performs a merge of two #ModulemdDefaultsV1 objects representing the
+ * defaults for a single module name. See the documentation for
+ * #ModulemdModuleIndexMerger for details on the merge algorithm used.
+ *
+ * Returns: (transfer full): A newly-allocated #ModulemdDefaultsV1 object
+ * containing the merged values of @from and @into. If this function encounters
+ * an unresolvable merge conflict, it will return NULL and set @error
+ * appropriately.
+ *
+ * Since: 2.0
+ */
ModulemdDefaults *
-modulemd_defaults_v1_merge (const gchar *module_name,
- ModulemdDefaultsV1 *from,
+modulemd_defaults_v1_merge (ModulemdDefaultsV1 *from,
ModulemdDefaultsV1 *into,
gboolean strict_default_streams,
GError **error);
diff --git a/modulemd/v2/modulemd-defaults-v1.c b/modulemd/v2/modulemd-defaults-v1.c
index f51e79d9b0a9fb0395077cd1c3be16529dd53f92..8a18d645de5d95a96e3cc862f78eeedc74595a9e 100644
--- a/modulemd/v2/modulemd-defaults-v1.c
+++ b/modulemd/v2/modulemd-defaults-v1.c
@@ -204,6 +204,7 @@ modulemd_defaults_v1_set_default_stream (ModulemdDefaultsV1 *self,
else
{
/* This is the fallback default for non-specific intents */
+ g_clear_pointer (&self->default_stream, g_free);
self->default_stream = g_strdup (default_stream);
}
}
@@ -1192,17 +1193,18 @@ modulemd_defaults_v1_emit_intents (ModulemdDefaultsV1 *self,
}
static gboolean
-modulemd_defaults_v1_merge_intent_profiles (
+modulemd_defaults_v1_merge_default_profiles (
GHashTable *from_profile_defaults,
GHashTable *merged_profile_defaults,
+ guint64 from_modified,
+ guint64 into_modified,
GError **error);
static GHashTable *
modulemd_defaults_v1_copy_intent_profiles (GHashTable *intent_profiles);
ModulemdDefaults *
-modulemd_defaults_v1_merge (const gchar *module_name,
- ModulemdDefaultsV1 *from,
+modulemd_defaults_v1_merge (ModulemdDefaultsV1 *from,
ModulemdDefaultsV1 *into,
gboolean strict_default_streams,
GError **error)
@@ -1212,83 +1214,85 @@ modulemd_defaults_v1_merge (const gchar *module_name,
gpointer key, value;
GHashTable *intent_profiles = NULL;
GHashTable *merged_intent_profiles = NULL;
+ guint64 from_modified;
+ guint64 into_modified;
g_autoptr (GHashTable) intent_profile_defaults = NULL;
gchar *intent_name = NULL;
gchar *intent_default_stream = NULL;
gchar *merged_default_stream = NULL;
g_autoptr (GError) nested_error = NULL;
+ const gchar *module_name =
+ modulemd_defaults_get_module_name (MODULEMD_DEFAULTS (into));
- merged = modulemd_defaults_v1_new (module_name);
+ from_modified = modulemd_defaults_get_modified (MODULEMD_DEFAULTS (from));
+ into_modified = modulemd_defaults_get_modified (MODULEMD_DEFAULTS (into));
+
+ /* Start from a copy of "into" */
+ merged =
+ MODULEMD_DEFAULTS_V1 (modulemd_defaults_copy (MODULEMD_DEFAULTS (into)));
/* Merge the default streams */
- if (into->default_stream && !from->default_stream)
- {
- modulemd_defaults_v1_set_default_stream (
- merged, into->default_stream, NULL);
- }
- else if (from->default_stream && !into->default_stream)
+ if (from->default_stream && !merged->default_stream)
{
modulemd_defaults_v1_set_default_stream (
merged, from->default_stream, NULL);
}
- else if (into->default_stream && from->default_stream)
+ else if (merged->default_stream && from->default_stream)
{
- if (g_str_equal (into->default_stream, DEFAULT_MERGE_CONFLICT))
+ if (g_str_equal (merged->default_stream, DEFAULT_MERGE_CONFLICT))
{
/* A previous pass over this same module encountered a merge
- * conflict, so we need to propagate that.
+ * conflict, so keep it.
*/
- modulemd_defaults_v1_set_default_stream (
- merged, DEFAULT_MERGE_CONFLICT, NULL);
}
- else if (!g_str_equal (into->default_stream, from->default_stream))
+ else if (!g_str_equal (merged->default_stream, from->default_stream))
{
- /* They have conflicting default streams */
- g_info ("Module stream mismatch in merge: %s != %s",
- into->default_stream,
- from->default_stream);
- if (strict_default_streams)
+ if (from_modified > into_modified)
{
- g_set_error (error,
- MODULEMD_ERROR,
- MODULEMD_ERROR_VALIDATE,
- "Default stream mismatch in module %s: %s != %s",
- module_name,
- into->default_stream,
- from->default_stream);
- return NULL;
+ modulemd_defaults_v1_set_default_stream (
+ merged, from->default_stream, NULL);
+ }
+ else if (from_modified == into_modified)
+ {
+ /* They have conflicting default streams */
+ g_info ("Module stream mismatch in merge: %s != %s",
+ into->default_stream,
+ from->default_stream);
+ if (strict_default_streams)
+ {
+ g_set_error (
+ error,
+ MODULEMD_ERROR,
+ MODULEMD_ERROR_VALIDATE,
+ "Default stream mismatch in module %s: %s != %s",
+ module_name,
+ into->default_stream,
+ from->default_stream);
+ return NULL;
+ }
+ modulemd_defaults_v1_set_default_stream (
+ merged, DEFAULT_MERGE_CONFLICT, NULL);
}
- modulemd_defaults_v1_set_default_stream (
- merged, DEFAULT_MERGE_CONFLICT, NULL);
}
else
{
- /* They're the same, so store that */
- modulemd_defaults_v1_set_default_stream (
- merged, into->default_stream, NULL);
+ /* They're the same, so change nothing */
}
}
else
{
- /* Both values were NULL.
- * Nothing to do, leave it blank.
- */
+ /* The 'from' default stream was NULL. Make no changes. */
}
/* == Merge profile defaults == */
- /* Iterate through 'into' and add them to merged_defaults */
- if (!modulemd_defaults_v1_merge_intent_profiles (
- into->profile_defaults, merged->profile_defaults, &nested_error))
- {
- g_propagate_error (error, g_steal_pointer (&nested_error));
- return NULL;
- }
-
/* Iterate through 'from' and see if there are additions or conflicts */
- if (!modulemd_defaults_v1_merge_intent_profiles (
- from->profile_defaults, merged->profile_defaults, &nested_error))
+ if (!modulemd_defaults_v1_merge_default_profiles (from->profile_defaults,
+ merged->profile_defaults,
+ from_modified,
+ into_modified,
+ &nested_error))
{
g_propagate_error (error, g_steal_pointer (&nested_error));
return NULL;
@@ -1298,18 +1302,6 @@ modulemd_defaults_v1_merge (const gchar *module_name,
/* Merge intent default stream values */
- /* Iterate through 'into' and add them to merged_defaults */
- g_hash_table_iter_init (&iter, into->intent_default_streams);
- while (g_hash_table_iter_next (&iter, &key, &value))
- {
- intent_name = (gchar *)key;
- intent_default_stream = (gchar *)value;
-
- g_hash_table_insert (merged->intent_default_streams,
- g_strdup (intent_name),
- g_strdup (intent_default_stream));
- }
-
/* Iterate through 'from', adding any new values and checking the existing
* ones for equivalence.
*/
@@ -1321,46 +1313,44 @@ modulemd_defaults_v1_merge (const gchar *module_name,
merged_default_stream =
g_hash_table_lookup (merged->intent_default_streams, intent_name);
+ /* If there is no new default stream, just jump to the next item */
+ if (!intent_default_stream)
+ continue;
+
if (!merged_default_stream)
{
/* New entry, just add it */
g_hash_table_insert (merged->intent_default_streams,
g_strdup (intent_name),
g_strdup (intent_default_stream));
- continue;
}
- if (!g_str_equal (intent_default_stream, merged_default_stream))
+ else if (!g_str_equal (intent_default_stream, merged_default_stream))
{
- g_set_error (error,
- MODULEMD_ERROR,
- MODULEMD_ERROR_VALIDATE,
- "Profile default stream mismatch in intents: %s != %s",
- intent_default_stream,
- merged_default_stream);
- return NULL;
+ if (from_modified > into_modified)
+ {
+ g_hash_table_replace (merged->intent_default_streams,
+ g_strdup (intent_name),
+ g_strdup (intent_default_stream));
+ }
+ else if (into_modified == from_modified)
+ {
+ g_set_error (
+ error,
+ MODULEMD_ERROR,
+ MODULEMD_ERROR_VALIDATE,
+ "Profile default stream mismatch in intents: %s != %s",
+ intent_default_stream,
+ merged_default_stream);
+ return NULL;
+ }
}
}
/* Merge intent default profile values */
- /* First copy 'into' to 'merged' */
- g_hash_table_iter_init (&iter, into->intent_default_profiles);
- while (g_hash_table_iter_next (&iter, &key, &value))
- {
- intent_name = (gchar *)key;
- intent_profiles = (GHashTable *)value;
-
- intent_profile_defaults =
- modulemd_defaults_v1_copy_intent_profiles (intent_profiles);
-
- g_hash_table_insert (merged->intent_default_profiles,
- g_strdup (intent_name),
- g_steal_pointer (&intent_profile_defaults));
- }
-
- /* Now copy 'from" into merged, checking for conflicts */
+ /* Now copy 'from' into merged, checking for conflicts */
g_hash_table_iter_init (&iter, from->intent_default_profiles);
while (g_hash_table_iter_next (&iter, &key, &value))
{
@@ -1374,7 +1364,7 @@ modulemd_defaults_v1_merge (const gchar *module_name,
intent_profile_defaults =
modulemd_defaults_v1_copy_intent_profiles (intent_profiles);
- /* This wasn't in 'into', so just add it */
+ /* This wasn't in 'merged', so just add it */
g_hash_table_insert (merged->intent_default_profiles,
g_strdup (intent_name),
g_steal_pointer (&intent_profile_defaults));
@@ -1384,14 +1374,20 @@ modulemd_defaults_v1_merge (const gchar *module_name,
/* Go through each of the profile defaults and see if they're additive or
* conflicting
*/
- if (!modulemd_defaults_v1_merge_intent_profiles (
- intent_profiles, merged_intent_profiles, &nested_error))
+ if (!modulemd_defaults_v1_merge_default_profiles (intent_profiles,
+ merged_intent_profiles,
+ from_modified,
+ into_modified,
+ &nested_error))
{
g_propagate_error (error, g_steal_pointer (&nested_error));
return NULL;
}
}
+ /* Set the modified value to the higher of the two provided */
+ if (from_modified > into_modified)
+ modulemd_defaults_set_modified (MODULEMD_DEFAULTS (merged), from_modified);
return MODULEMD_DEFAULTS (g_steal_pointer (&merged));
}
@@ -1427,9 +1423,11 @@ modulemd_defaults_v1_copy_intent_profiles (GHashTable *intent_profiles)
}
static gboolean
-modulemd_defaults_v1_merge_intent_profiles (
+modulemd_defaults_v1_merge_default_profiles (
GHashTable *from_profile_defaults,
GHashTable *merged_profile_defaults,
+ guint64 from_modified,
+ guint64 into_modified,
GError **error)
{
GHashTableIter iter;
@@ -1459,15 +1457,30 @@ modulemd_defaults_v1_merge_intent_profiles (
/* Check to see if they match */
if (!modulemd_hash_table_sets_are_equal (from_profiles, merged_profiles))
{
- /* The profile sets differed. This is an unresolvable merge
- * conflict
- */
- g_set_error (error,
- MODULEMD_ERROR,
- MODULEMD_ERROR_VALIDATE,
- "Profile default mismatch in stream: %s",
- stream_name);
- return FALSE;
+ if (from_modified > into_modified)
+ {
+ g_hash_table_replace (
+ merged_profile_defaults,
+ g_strdup (stream_name),
+ modulemd_hash_table_deep_set_copy (from_profiles));
+ }
+ else if (into_modified > from_modified)
+ {
+ /* Already there, so just continue */
+ continue;
+ }
+ else
+ {
+ /* The profile sets differed. This is an unresolvable merge
+ * conflict
+ */
+ g_set_error (error,
+ MODULEMD_ERROR,
+ MODULEMD_ERROR_VALIDATE,
+ "Profile default mismatch in stream: %s",
+ stream_name);
+ return FALSE;
+ }
}
/* They were a complete match, so no need to add it a second time */
diff --git a/modulemd/v2/modulemd-defaults.c b/modulemd/v2/modulemd-defaults.c
index 2157f21fd4079ee096baee2a3a3552df5c273d06..b551c578fda68a8a1ae7532696548e8c18501e68 100644
--- a/modulemd/v2/modulemd-defaults.c
+++ b/modulemd/v2/modulemd-defaults.c
@@ -396,9 +396,6 @@ modulemd_defaults_merge (ModulemdDefaults *from,
{
g_autoptr (ModulemdDefaults) merged_defaults = NULL;
guint64 mdversion;
- const gchar *module_name = NULL;
- guint64 from_modified;
- guint64 into_modified;
g_autoptr (GError) nested_error = NULL;
g_return_val_if_fail (MODULEMD_IS_DEFAULTS (from), NULL);
@@ -416,36 +413,19 @@ modulemd_defaults_merge (ModulemdDefaults *from,
NULL);
g_return_val_if_fail (mdversion == MD_DEFAULTS_VERSION_ONE, NULL);
- from_modified = modulemd_defaults_get_modified (from);
- into_modified = modulemd_defaults_get_modified (into);
-
- if (from_modified > into_modified)
- {
- /* Just return 'from' if it has a higher modified value */
- return modulemd_defaults_copy (from);
- }
- else if (into_modified > from_modified)
- {
- /* Just return 'into' if it has a higher modified value */
- return modulemd_defaults_copy (into);
- }
-
- /* Modified value is the same, so we need to merge */
-
- module_name = modulemd_defaults_get_module_name (into);
- if (!g_str_equal (module_name, modulemd_defaults_get_module_name (from)))
+ if (!g_str_equal (modulemd_defaults_get_module_name (into),
+ modulemd_defaults_get_module_name (from)))
{
g_set_error (error,
MODULEMD_ERROR,
MODULEMD_ERROR_VALIDATE,
"Module name mismatch in merge: %s != %s",
- module_name,
+ modulemd_defaults_get_module_name (into),
modulemd_defaults_get_module_name (from));
return NULL;
}
- merged_defaults = modulemd_defaults_v1_merge (module_name,
- MODULEMD_DEFAULTS_V1 (from),
+ merged_defaults = modulemd_defaults_v1_merge (MODULEMD_DEFAULTS_V1 (from),
MODULEMD_DEFAULTS_V1 (into),
strict_default_streams,
&nested_error);
diff --git a/modulemd/v2/tests/ModulemdTests/merger.py b/modulemd/v2/tests/ModulemdTests/merger.py
index 92c90d185f55b8a7d5f856aa16cdce5ff32f30d8..72bd43f9d775923abf6a456c70b01bf3d0a912fc 100644
--- a/modulemd/v2/tests/ModulemdTests/merger.py
+++ b/modulemd/v2/tests/ModulemdTests/merger.py
@@ -14,6 +14,7 @@
from os import path
import sys
+import logging
try:
import unittest
import gi
@@ -231,6 +232,124 @@ data:
with self.assertRaisesRegexp(gi.repository.GLib.GError, "Default stream mismatch in module python"):
merger.resolve_ext(True)
+ def test_merge_add_only(self):
+ base_idx = Modulemd.ModuleIndex()
+ self.assertTrue(base_idx.update_from_file(
+ path.join(
+ self.test_data_path,
+ "merger",
+ "base.yaml"), True))
+
+ add_only_idx = Modulemd.ModuleIndex()
+ self.assertTrue(add_only_idx.update_from_file(
+ path.join(
+ self.test_data_path,
+ "merger",
+ "add_only.yaml"), True))
+
+ merger = Modulemd.ModuleIndexMerger()
+ merger.associate_index(base_idx, 0)
+ merger.associate_index(add_only_idx, 0)
+
+ merged_idx = merger.resolve()
+ self.assertIsNotNone(merged_idx)
+
+ httpd = merged_idx.get_module('httpd')
+ self.assertIsNotNone(httpd)
+ httpd_defs = httpd.get_defaults()
+
+ self.assertEqual(httpd_defs.get_default_stream(), "2.8")
+ expected_profile_defs = {
+ '2.2': set(['client', 'server']),
+ '2.8': set(['notreal', ]),
+ '2.10': set(['notreal', ])
+ }
+
+ for stream in expected_profile_defs.keys():
+ self.assertEqual(set(httpd_defs.get_default_profiles_for_stream(
+ stream)), expected_profile_defs[stream])
+
+ self.assertEqual(httpd_defs.get_default_stream("workstation"), "2.4")
+
+ def test_merge_add_conflicting_stream(self):
+ base_idx = Modulemd.ModuleIndex()
+ self.assertTrue(base_idx.update_from_file(
+ path.join(
+ self.test_data_path,
+ "merger",
+ "base.yaml"), True))
+
+ add_only_idx = Modulemd.ModuleIndex()
+ self.assertTrue(add_only_idx.update_from_file(
+ path.join(
+ self.test_data_path,
+ "merger",
+ "add_conflicting_stream.yaml"), True))
+
+ merger = Modulemd.ModuleIndexMerger()
+ merger.associate_index(base_idx, 0)
+ merger.associate_index(add_only_idx, 0)
+
+ merged_idx = merger.resolve()
+ self.assertIsNotNone(merged_idx)
+
+ psql = merged_idx.get_module('postgresql')
+ self.assertIsNotNone(psql)
+
+ psql_defs = psql.get_defaults()
+ self.assertIsNotNone(psql_defs)
+
+ self.assertIsNone(psql_defs.get_default_stream())
+
+ expected_profile_defs = {
+ '8.1': set(['client', 'server', 'foo']),
+ '8.2': set(['client', 'server', 'foo']),
+ }
+
+ for stream in expected_profile_defs.keys():
+ self.assertEqual(set(psql_defs.get_default_profiles_for_stream(
+ stream)), expected_profile_defs[stream])
+
+ def test_merge_add_conflicting_stream_and_profile_modified(self):
+ base_idx = Modulemd.ModuleIndex()
+ self.assertTrue(base_idx.update_from_file(
+ path.join(
+ self.test_data_path,
+ "merger",
+ "base.yaml"), True))
+
+ add_conflicting_idx = Modulemd.ModuleIndex()
+ self.assertTrue(add_conflicting_idx.update_from_file(
+ path.join(
+ self.test_data_path,
+ "merger",
+ "add_conflicting_stream_and_profile_modified.yaml"), True))
+
+ merger = Modulemd.ModuleIndexMerger()
+ merger.associate_index(base_idx, 0)
+ merger.associate_index(add_conflicting_idx, 0)
+
+ merged_idx = merger.resolve()
+ self.assertIsNotNone(merged_idx)
+
+ psql = merged_idx.get_module('postgresql')
+ self.assertIsNotNone(psql)
+
+ psql_defs = psql.get_defaults()
+ self.assertIsNotNone(psql_defs)
+
+ self.assertEqual(psql_defs.get_default_stream(), '8.2')
+
+ expected_profile_defs = {
+ '8.1': set(['client', 'server']),
+ '8.2': set(['client', 'server', 'foo']),
+ '8.3': set(['client', 'server']),
+ }
+
+ for stream in expected_profile_defs:
+ self.assertEqual(set(psql_defs.get_default_profiles_for_stream(
+ stream)), expected_profile_defs[stream])
+
if __name__ == '__main__':
unittest.main()
diff --git a/modulemd/v2/tests/test-modulemd-merger.c b/modulemd/v2/tests/test-modulemd-merger.c
index e46b4d84441528310c2d4e5b5990f23e3719090e..967e2cc902a5708905e9762e4d4631ab2eb4e4eb 100644
--- a/modulemd/v2/tests/test-modulemd-merger.c
+++ b/modulemd/v2/tests/test-modulemd-merger.c
@@ -14,6 +14,8 @@
#include <glib.h>
#include <yaml.h>
+#include "modulemd-defaults.h"
+#include "modulemd-defaults-v1.h"
#include "modulemd-module-index.h"
#include "modulemd-module-index-merger.h"
#include "private/test-utils.h"
@@ -101,6 +103,142 @@ merger_test_deduplicate (CommonMmdTestFixture *fixture,
}
+static void
+merger_test_add_only (void)
+{
+ g_autoptr (GPtrArray) failures = NULL;
+ g_autoptr (GError) error = NULL;
+ g_autoptr (ModulemdModuleIndex) base_idx = modulemd_module_index_new ();
+ g_autoptr (ModulemdModuleIndex) add_only_idx = modulemd_module_index_new ();
+ g_autoptr (ModulemdModuleIndex) merged_idx = NULL;
+ g_autoptr (ModulemdModuleIndexMerger) merger =
+ modulemd_module_index_merger_new ();
+ ModulemdModule *httpd = NULL;
+ ModulemdDefaults *httpd_defs = NULL;
+ g_autofree gchar *base_yaml =
+ g_strdup_printf ("%s/merger/base.yaml", g_getenv ("TEST_DATA_PATH"));
+ g_autofree gchar *add_only_yaml =
+ g_strdup_printf ("%s/merger/add_only.yaml", g_getenv ("TEST_DATA_PATH"));
+
+ g_assert_true (modulemd_module_index_update_from_file (
+ base_idx, base_yaml, TRUE, &failures, &error));
+ g_assert_true (modulemd_module_index_update_from_file (
+ add_only_idx, add_only_yaml, TRUE, &failures, &error));
+
+ modulemd_module_index_merger_associate_index (merger, base_idx, 0);
+ modulemd_module_index_merger_associate_index (merger, add_only_idx, 0);
+
+ merged_idx = modulemd_module_index_merger_resolve_ext (merger, TRUE, &error);
+ g_assert_no_error (error);
+ g_assert_nonnull (merged_idx);
+
+ httpd = modulemd_module_index_get_module (merged_idx, "httpd");
+ g_assert_nonnull (httpd);
+
+ httpd_defs = modulemd_module_get_defaults (httpd);
+ g_assert_nonnull (httpd_defs);
+
+ g_assert_cmpstr (modulemd_defaults_v1_get_default_stream (
+ MODULEMD_DEFAULTS_V1 (httpd_defs), NULL),
+ ==,
+ "2.8");
+
+ g_assert_cmpstr (modulemd_defaults_v1_get_default_stream (
+ MODULEMD_DEFAULTS_V1 (httpd_defs), "workstation"),
+ ==,
+ "2.4");
+}
+
+
+static void
+merger_test_add_conflicting_stream (void)
+{
+ g_autoptr (GPtrArray) failures = NULL;
+ g_autoptr (GError) error = NULL;
+ g_autoptr (ModulemdModuleIndex) base_idx = modulemd_module_index_new ();
+ g_autoptr (ModulemdModuleIndex) add_conflicting_idx =
+ modulemd_module_index_new ();
+ g_autoptr (ModulemdModuleIndex) merged_idx = NULL;
+ g_autoptr (ModulemdModuleIndexMerger) merger =
+ modulemd_module_index_merger_new ();
+ ModulemdModule *psql = NULL;
+ ModulemdDefaults *psql_defs = NULL;
+ g_autofree gchar *base_yaml =
+ g_strdup_printf ("%s/merger/base.yaml", g_getenv ("TEST_DATA_PATH"));
+ g_autofree gchar *add_conflicting_yaml = g_strdup_printf (
+ "%s/merger/add_conflicting_stream.yaml", g_getenv ("TEST_DATA_PATH"));
+
+ g_assert_true (modulemd_module_index_update_from_file (
+ base_idx, base_yaml, TRUE, &failures, &error));
+ g_assert_true (modulemd_module_index_update_from_file (
+ add_conflicting_idx, add_conflicting_yaml, TRUE, &failures, &error));
+
+ modulemd_module_index_merger_associate_index (merger, base_idx, 0);
+ modulemd_module_index_merger_associate_index (
+ merger, add_conflicting_idx, 0);
+
+ merged_idx =
+ modulemd_module_index_merger_resolve_ext (merger, FALSE, &error);
+ g_assert_no_error (error);
+ g_assert_nonnull (merged_idx);
+
+ psql = modulemd_module_index_get_module (merged_idx, "postgresql");
+ g_assert_nonnull (psql);
+
+ psql_defs = modulemd_module_get_defaults (psql);
+ g_assert_nonnull (psql_defs);
+
+ g_assert_null (modulemd_defaults_v1_get_default_stream (
+ MODULEMD_DEFAULTS_V1 (psql_defs), NULL));
+}
+
+
+static void
+merger_test_add_conflicting_stream_and_profile_modified (void)
+{
+ g_autoptr (GPtrArray) failures = NULL;
+ g_autoptr (GError) error = NULL;
+ g_autoptr (ModulemdModuleIndex) base_idx = modulemd_module_index_new ();
+ g_autoptr (ModulemdModuleIndex) add_conflicting_idx =
+ modulemd_module_index_new ();
+ g_autoptr (ModulemdModuleIndex) merged_idx = NULL;
+ g_autoptr (ModulemdModuleIndexMerger) merger =
+ modulemd_module_index_merger_new ();
+ ModulemdModule *psql = NULL;
+ ModulemdDefaults *psql_defs = NULL;
+ g_autofree gchar *base_yaml =
+ g_strdup_printf ("%s/merger/base.yaml", g_getenv ("TEST_DATA_PATH"));
+ g_autofree gchar *add_conflicting_yaml = g_strdup_printf (
+ "%s/merger/add_conflicting_stream_and_profile_modified.yaml",
+ g_getenv ("TEST_DATA_PATH"));
+
+ g_assert_true (modulemd_module_index_update_from_file (
+ base_idx, base_yaml, TRUE, &failures, &error));
+ g_assert_true (modulemd_module_index_update_from_file (
+ add_conflicting_idx, add_conflicting_yaml, TRUE, &failures, &error));
+
+ modulemd_module_index_merger_associate_index (merger, base_idx, 0);
+ modulemd_module_index_merger_associate_index (
+ merger, add_conflicting_idx, 0);
+
+ merged_idx =
+ modulemd_module_index_merger_resolve_ext (merger, FALSE, &error);
+ g_assert_no_error (error);
+ g_assert_nonnull (merged_idx);
+
+ psql = modulemd_module_index_get_module (merged_idx, "postgresql");
+ g_assert_nonnull (psql);
+
+ psql_defs = modulemd_module_get_defaults (psql);
+ g_assert_nonnull (psql_defs);
+
+ g_assert_cmpstr (modulemd_defaults_v1_get_default_stream (
+ MODULEMD_DEFAULTS_V1 (psql_defs), NULL),
+ ==,
+ "8.2");
+}
+
+
int
main (int argc, char *argv[])
{
@@ -125,5 +263,14 @@ main (int argc, char *argv[])
merger_test_deduplicate,
NULL);
+ g_test_add_func ("/modulemd/module/index/merger/add_only",
+ merger_test_add_only);
+
+ g_test_add_func ("/modulemd/module/index/merger/add_conflicting_stream",
+ merger_test_add_conflicting_stream);
+
+ g_test_add_func ("/modulemd/module/index/merger/add_conflicting_both",
+ merger_test_add_conflicting_stream_and_profile_modified);
+
return g_test_run ();
}
--
2.23.0

View File

@ -1,503 +0,0 @@
From a16e69a71778bc81e5bb35ab98048a650cd4edcc Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Tue, 8 Oct 2019 16:05:13 -0400
Subject: [PATCH 8/8] Rework defaults merging logic
Fixes: https://github.com/fedora-modularity/libmodulemd/issues/378
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
---
modulemd/v1/modulemd-defaults.c | 347 +++++++++++++-------
modulemd/v1/tests/test-modulemd-defaults.c | 18 +-
test_data/defaults/overriding-modified.yaml | 5 +-
3 files changed, 242 insertions(+), 128 deletions(-)
diff --git a/modulemd/v1/modulemd-defaults.c b/modulemd/v1/modulemd-defaults.c
index d44076eef0ac3bffae05f74b852fb6b51c2aee64..9fa00f4104938f83e023070e6971608b0d27ddfa 100644
--- a/modulemd/v1/modulemd-defaults.c
+++ b/modulemd/v1/modulemd-defaults.c
@@ -725,27 +725,36 @@ modulemd_defaults_copy (ModulemdDefaults *self)
}
+static gboolean
+modulemd_defaults_merge_default_profiles (GHashTable *from_profile_defaults,
+ GHashTable *merged_profile_defaults,
+ guint64 from_modified,
+ guint64 into_modified,
+ GError **error);
+
+static void
+modulemd_defaults_merge_intent_default_streams (ModulemdIntent *from_intent,
+ ModulemdIntent *into_intent,
+ const gchar *intent_name,
+ guint64 from_modified,
+ guint64 into_modified);
+
ModulemdDefaults *
modulemd_defaults_merge (ModulemdDefaults *first,
ModulemdDefaults *second,
gboolean override,
GError **error)
{
- g_autoptr (ModulemdDefaults) defaults = NULL;
- GHashTable *profile_defaults = NULL;
- g_autoptr (GHashTable) intents = NULL;
- ModulemdIntent *base_intent = NULL;
- ModulemdIntent *merge_intent = NULL;
- g_autoptr (ModulemdIntent) new_intent = NULL;
- g_autoptr (GHashTable) base_profiles = NULL;
- GHashTable *merge_profiles = NULL;
+ g_autoptr (ModulemdDefaults) merged = NULL;
+ ModulemdIntent *from_intent = NULL;
+ ModulemdIntent *merged_intent = NULL;
const gchar *intent_name = NULL;
- ModulemdSimpleSet *profile = NULL;
- GHashTableIter iter, profile_iter;
- gpointer key, value, orig_value, prof_key, prof_value;
+ GHashTableIter iter;
+ gpointer key, value;
- g_return_val_if_fail (MODULEMD_IS_DEFAULTS (first), NULL);
- g_return_val_if_fail (MODULEMD_IS_DEFAULTS (second), NULL);
+
+ g_return_val_if_fail (first && MODULEMD_IS_DEFAULTS (first), NULL);
+ g_return_val_if_fail (second && MODULEMD_IS_DEFAULTS (second), NULL);
if (override)
{
@@ -755,156 +764,250 @@ modulemd_defaults_merge (ModulemdDefaults *first,
return modulemd_defaults_copy (second);
}
- /* Compare modified values */
- if (modulemd_defaults_get_modified (first) >
- modulemd_defaults_get_modified (second))
+ /* Start from a copy of the base */
+ merged = modulemd_defaults_copy (first);
+
+ /* == Merge default streams == */
+ if (second->default_stream && !merged->default_stream)
{
- /* If first has a higher modified value, return a copy of it */
- return modulemd_defaults_copy (first);
+ /* Only the second Defaults had a default stream, so set that */
+ modulemd_defaults_set_default_stream (merged, second->default_stream);
}
- else if (modulemd_defaults_get_modified (second) >
- modulemd_defaults_get_modified (first))
+ else if (merged->default_stream && second->default_stream)
{
- /* If second has a higher modified value, return a copy of it */
- return modulemd_defaults_copy (second);
- }
-
+ /* Both of them had a defaults set */
- /* They had the same 'modified' value (such as both zero, for
- * backwards-compatibility with 1.7.x and older.
- * Merge them as best we can.
- */
-
- defaults = modulemd_defaults_copy (first);
-
- /* First check for incompatibilities with the streams */
- if (g_strcmp0 (first->default_stream, second->default_stream))
- {
- /* Default streams don't match and override is not set.
- * Return an error
+ /* Shortcut past if we already know there are conflicts in this
+ * default stream.
*/
- /* They have conflicting default streams */
- g_info ("Module stream mismatch in merge: %s != %s",
- first->default_stream,
- second->default_stream);
- modulemd_defaults_set_default_stream (defaults, DEFAULT_MERGE_CONFLICT);
- }
-
- /* Merge the profile defaults */
- profile_defaults = modulemd_defaults_peek_profile_defaults (defaults);
-
- g_hash_table_iter_init (&iter,
- modulemd_defaults_peek_profile_defaults (second));
- while (g_hash_table_iter_next (&iter, &key, &value))
- {
- orig_value = g_hash_table_lookup (profile_defaults, key);
- if (orig_value)
+ if (!g_str_equal (merged->default_stream, DEFAULT_MERGE_CONFLICT))
{
- /* This key already exists in the first defaults object.
- * Check whether they have identical values
+ /* If second has a higher modified value, use its value.
+ * If first has a higher modified value, it's already saved in
+ * merged from the copy()
*/
- if (!modulemd_simpleset_is_equal (orig_value, value))
+ if (second->modified > first->modified)
{
- g_set_error (error,
- MODULEMD_DEFAULTS_ERROR,
- MODULEMD_DEFAULTS_ERROR_CONFLICTING_PROFILES,
- "Conflicting profile defaults when merging "
- "defaults for module %s",
- modulemd_defaults_peek_module_name (first));
- return NULL;
+ modulemd_defaults_set_default_stream (merged,
+ second->default_stream);
+ }
+ else if (first->modified == second->modified)
+ {
+ if (!g_str_equal (first->default_stream, second->default_stream))
+ {
+ /* They have conflicting default streams */
+ g_info ("Module stream mismatch in merge: %s != %s",
+ first->default_stream,
+ second->default_stream);
+
+ /* Set the special conflicting value */
+ modulemd_defaults_set_default_stream (
+ merged, DEFAULT_MERGE_CONFLICT);
+ }
+ /* Otherwise, they are the same and merged will have the correct
+ * value from the copy()
+ */
}
- }
- else
- {
- /* This key is new. Add it */
- g_hash_table_replace (profile_defaults,
- g_strdup (key),
- g_object_ref (MODULEMD_SIMPLESET (value)));
}
}
+ /* If neither of the above matched, both first and second had NULL for the
+ * default stream, so nothing to do
+ */
+
+
+ /* == Merge profile defaults == */
+ if (!modulemd_defaults_merge_default_profiles (second->profile_defaults,
+ merged->profile_defaults,
+ second->modified,
+ first->modified,
+ error))
+ {
+ return NULL;
+ }
+
+
+ /* == Merge intent defaults == */
+ /* --- Merge intent default stream values --- */
- /* Merge intents */
- intents = modulemd_defaults_dup_intents (defaults);
+ /* Iterate through 'second', adding any new values and checking the existing
+ * ones for equivalence.
+ */
g_hash_table_iter_init (&iter, modulemd_defaults_peek_intents (second));
while (g_hash_table_iter_next (&iter, &key, &value))
{
- merge_intent = MODULEMD_INTENT (value);
- /* Check if this module name exists in the current table */
- intent_name = modulemd_intent_peek_intent_name (merge_intent);
- base_intent = g_hash_table_lookup (
- intents, modulemd_intent_peek_intent_name (merge_intent));
+ g_return_val_if_fail (value && MODULEMD_IS_INTENT (value), FALSE);
- if (!base_intent)
+ intent_name = (gchar *)key;
+ from_intent = MODULEMD_INTENT (value);
+
+ merged_intent = g_hash_table_lookup (merged->intents, intent_name);
+ if (!merged_intent)
{
/* This intent doesn't exist yet, so just add it completely. */
- g_hash_table_insert (intents,
+ g_hash_table_insert (merged->intents,
g_strdup (intent_name),
- modulemd_intent_copy (merge_intent));
+ modulemd_intent_copy (from_intent));
continue;
}
- /* Compare the default stream for this intent */
- if (g_strcmp0 (modulemd_intent_peek_default_stream (base_intent),
- modulemd_intent_peek_default_stream (merge_intent)))
+ /* Merge the intent default streams */
+ modulemd_defaults_merge_intent_default_streams (from_intent,
+ merged_intent,
+ intent_name,
+ second->modified,
+ first->modified);
+
+ /* Merge the intent default profiles */
+ if (!modulemd_defaults_merge_default_profiles (
+ modulemd_intent_peek_profile_defaults (from_intent),
+ modulemd_intent_peek_profile_defaults (merged_intent),
+ second->modified,
+ first->modified,
+ error))
{
- /* The streams didn't match, so bail out */
- g_set_error (error,
- MODULEMD_DEFAULTS_ERROR,
- MODULEMD_DEFAULTS_ERROR_CONFLICTING_INTENT_STREAM,
- "Conflicting default stream for intent profile [%s]"
- "when merging defaults for module %s",
- (const gchar *)intent_name,
- modulemd_defaults_peek_module_name (first));
return NULL;
}
+ }
- /* Construct a new Intent with the merged values which will replace
- * the existing one at the end */
- new_intent = modulemd_intent_copy (base_intent);
+ /* Set the modified value to the higher of the two provided */
+ if (second->modified > first->modified)
+ modulemd_defaults_set_modified (merged, second->modified);
- /* Merge the profile definitions for this intent */
- base_profiles = modulemd_intent_dup_profile_defaults (new_intent);
+ return g_steal_pointer (&merged);
+}
- merge_profiles = modulemd_intent_peek_profile_defaults (merge_intent);
- g_hash_table_iter_init (&profile_iter, merge_profiles);
- while (g_hash_table_iter_next (&profile_iter, &prof_key, &prof_value))
+
+static gboolean
+modulemd_defaults_merge_default_profiles (GHashTable *from_profile_defaults,
+ GHashTable *merged_profile_defaults,
+ guint64 from_modified,
+ guint64 into_modified,
+ GError **error)
+{
+ GHashTableIter iter;
+ gpointer key, value;
+ gchar *stream_name = NULL;
+ ModulemdSimpleSet *from_profiles = NULL;
+ ModulemdSimpleSet *merged_profiles = NULL;
+ ModulemdSimpleSet *copied_profiles = NULL;
+
+ g_hash_table_iter_init (&iter, from_profile_defaults);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ {
+ stream_name = (gchar *)key;
+ from_profiles = (ModulemdSimpleSet *)value;
+ merged_profiles =
+ g_hash_table_lookup (merged_profile_defaults, stream_name);
+
+ if (!merged_profiles)
{
- /* Check if this profile exists in this intent */
- profile = g_hash_table_lookup (base_profiles, prof_key);
+ /* Didn't appear in the profiles list, so just add it to merged */
+ modulemd_simpleset_copy (from_profiles, &copied_profiles);
+ g_hash_table_insert (
+ merged_profile_defaults, g_strdup (stream_name), copied_profiles);
+ copied_profiles = NULL;
+ continue;
+ }
- if (!profile)
+ /* Check to see if they match */
+ if (!modulemd_simpleset_is_equal (from_profiles, merged_profiles))
+ {
+ if (from_modified > into_modified)
+ {
+ modulemd_simpleset_copy (from_profiles, &copied_profiles);
+ g_hash_table_insert (merged_profile_defaults,
+ g_strdup (stream_name),
+ copied_profiles);
+ copied_profiles = NULL;
+ }
+ else if (into_modified > from_modified)
{
- /* Add this profile to the intent */
- modulemd_simpleset_copy (prof_value, &profile);
- g_hash_table_insert (
- base_profiles, g_strdup ((const gchar *)prof_key), profile);
+ /* Already there, so just continue */
continue;
}
-
- if (!modulemd_simpleset_is_equal (profile, prof_value))
+ else
{
- /* If we get here, the sets were unequal, so we need to fail */
+ /* The profile sets differed. This is an unresolvable merge
+ * conflict
+ */
g_set_error (error,
MODULEMD_DEFAULTS_ERROR,
- MODULEMD_DEFAULTS_ERROR_CONFLICTING_INTENT_PROFILE,
- "Conflicting intent profile [%s:%s] when merging "
- "defaults for module %s",
- (const gchar *)intent_name,
- (const gchar *)prof_key,
- modulemd_defaults_peek_module_name (first));
- return NULL;
+ MODULEMD_DEFAULTS_ERROR_CONFLICTING_PROFILES,
+ "Profile default mismatch in stream: %s",
+ stream_name);
+ return FALSE;
}
}
- modulemd_intent_set_profile_defaults (new_intent, base_profiles);
- g_clear_pointer (&base_profiles, g_hash_table_unref);
- g_hash_table_replace (
- intents, g_strdup (intent_name), g_object_ref (new_intent));
- g_clear_pointer (&new_intent, g_object_unref);
+ /* They were a complete match, so no need to add it a second time */
}
- modulemd_defaults_set_intents (defaults, intents);
+ return TRUE;
+}
+
+static void
+modulemd_defaults_merge_intent_default_streams (ModulemdIntent *from_intent,
+ ModulemdIntent *into_intent,
+ const gchar *intent_name,
+ guint64 from_modified,
+ guint64 into_modified)
+{
+ const gchar *from_default_stream = NULL;
+ const gchar *into_default_stream = NULL;
+
+ g_return_if_fail (from_intent && MODULEMD_IS_INTENT (from_intent));
+ g_return_if_fail (into_intent && MODULEMD_IS_INTENT (into_intent));
+ g_return_if_fail (intent_name);
+
+ from_default_stream = modulemd_intent_peek_default_stream (from_intent);
+
+ /* If there is no new default stream, just jump to the next item */
+ if (!from_default_stream)
+ return;
+
+ into_default_stream = modulemd_intent_peek_default_stream (into_intent);
+
+
+ /* If a previous merge has already marked this as conflicting, just bail
+ * out here and move on to the next intent
+ */
+ if (g_str_equal (into_default_stream, DEFAULT_MERGE_CONFLICT))
+ return;
- return g_object_ref (defaults);
+
+ if (into_default_stream)
+ {
+ /* Both default stream names are present.
+ * If they are equal, there's nothing to do.
+ */
+
+ if (!g_str_equal (into_default_stream, from_default_stream))
+ {
+ if (from_modified > into_modified)
+ {
+ /* Set the default stream of from as the merged value */
+ modulemd_intent_set_default_stream (into_intent,
+ from_default_stream);
+ return;
+ }
+ else if (into_modified == from_modified)
+ {
+ g_info (
+ "Module stream mismatch in merge: %s != %s for intent %s",
+ into_default_stream,
+ from_default_stream,
+ intent_name);
+ modulemd_intent_set_default_stream (into_intent,
+ DEFAULT_MERGE_CONFLICT);
+ return;
+ }
+ /* Otherwise into is already set, so do nothing */
+ }
+ }
+ else /* !into_default_stream */
+ {
+ /* There was no default stream set yet, so just add the new one */
+ modulemd_intent_set_default_stream (into_intent, from_default_stream);
+ }
}
diff --git a/modulemd/v1/tests/test-modulemd-defaults.c b/modulemd/v1/tests/test-modulemd-defaults.c
index 35142b885b3ec30f5109d53befe17be3e08d7b5a..c088e87b442af37e69845216db33afa8361785cc 100644
--- a/modulemd/v1/tests/test-modulemd-defaults.c
+++ b/modulemd/v1/tests/test-modulemd-defaults.c
@@ -913,7 +913,7 @@ modulemd_defaults_test_prioritizer_modified (DefaultsFixture *fixture,
g_assert_cmpstr (
modulemd_defaults_peek_default_stream (defaults), ==, "2.4");
htable = modulemd_defaults_peek_profile_defaults (defaults);
- g_assert_cmpint (g_hash_table_size (htable), ==, 2);
+ g_assert_cmpint (g_hash_table_size (htable), ==, 3);
g_assert_true (g_hash_table_contains (htable, "2.2"));
g_assert_true (modulemd_simpleset_contains (
g_hash_table_lookup (htable, "2.2"), "client"));
@@ -924,7 +924,10 @@ modulemd_defaults_test_prioritizer_modified (DefaultsFixture *fixture,
g_hash_table_lookup (htable, "2.2"), "client"));
g_assert_true (modulemd_simpleset_contains (
g_hash_table_lookup (htable, "2.4"), "server"));
- g_assert_false (g_hash_table_contains (htable, "2.8"));
+ g_assert_true (g_hash_table_contains (htable, "2.8"));
+ g_assert_true (modulemd_simpleset_contains (
+ g_hash_table_lookup (htable, "2.8"), "notreal"));
+
/* NODEJS */
defaults = MODULEMD_DEFAULTS (g_ptr_array_index (merged_objects, 1));
@@ -956,14 +959,21 @@ modulemd_defaults_test_prioritizer_modified (DefaultsFixture *fixture,
g_assert_cmpstr (
modulemd_defaults_peek_default_stream (defaults), ==, "8.1");
htable = modulemd_defaults_peek_profile_defaults (defaults);
- g_assert_cmpint (g_hash_table_size (htable), ==, 1);
+ g_assert_cmpint (g_hash_table_size (htable), ==, 2);
g_assert_true (g_hash_table_contains (htable, "8.1"));
g_assert_true (modulemd_simpleset_contains (
g_hash_table_lookup (htable, "8.1"), "client"));
g_assert_true (modulemd_simpleset_contains (
g_hash_table_lookup (htable, "8.1"), "server"));
- g_assert_true (
+ g_assert_false (
modulemd_simpleset_contains (g_hash_table_lookup (htable, "8.1"), "foo"));
+ g_assert_true (g_hash_table_contains (htable, "8.2"));
+ g_assert_true (modulemd_simpleset_contains (
+ g_hash_table_lookup (htable, "8.2"), "client"));
+ g_assert_true (modulemd_simpleset_contains (
+ g_hash_table_lookup (htable, "8.2"), "server"));
+ g_assert_true (
+ modulemd_simpleset_contains (g_hash_table_lookup (htable, "8.2"), "foo"));
}
diff --git a/test_data/defaults/overriding-modified.yaml b/test_data/defaults/overriding-modified.yaml
index 719892ee0e999e4c48a9c69f6d4fdf84b0c5d89d..b87ba98ca99da128f78f8c560af3a7d928e8fde9 100644
--- a/test_data/defaults/overriding-modified.yaml
+++ b/test_data/defaults/overriding-modified.yaml
@@ -17,7 +17,7 @@ data:
'2.6': [client, server, bindings]
'2.8': [client, server, bindings, new]
---
-# Reduce the number of profile defaults
+# Drop one profile from a stream and add it to another
document: modulemd-defaults
version: 1
data:
@@ -25,7 +25,8 @@ data:
modified: 201812061200
stream: '8.1'
profiles:
- '8.1': [client, server, foo]
+ '8.1': [client, server]
+ '8.2': [client, server, foo]
---
# Override the default stream
document: modulemd-defaults
--
2.23.0

View File

@ -1,14 +1,25 @@
%global libmodulemd_version 2.5.0 %global baserelease 1
%global libmodulemd_v1_version 1.8.11 %global v2_epoch 0
%global v2_major 2
%global v2_minor 8
%global v2_patch 2
%global v2_release %{baserelease}
%global libmodulemd_v2_version %{v2_major}.%{v2_minor}.%{v2_patch}
%global libmodulemd_v1_version 1.8.16
# This is trickery to ensure that the upgrade path for libmodulemd1 is always
# clean and associated with the appropriate v2 build
%global libmodulemd_v1_release %{v2_epoch}.%{v2_major}.%{v2_minor}.%{v2_patch}.%{v2_release}
Name: libmodulemd Name: libmodulemd
Version: %{libmodulemd_version} Version: %{libmodulemd_v2_version}
Release: 4%{?dist} Release: %{baserelease}%{?dist}
Summary: Module metadata manipulation library Summary: Module metadata manipulation library
License: MIT License: MIT
URL: https://github.com/fedora-modularity/libmodulemd URL: https://github.com/fedora-modularity/libmodulemd
Source0: %{url}/releases/download/%{name}-%{version}/modulemd-%{version}.tar.xz Source0: %{url}/releases/download/%{name}-%{version}/modulemd-%{version}.tar.xz
Source1: %{url}/releases/download/%{name}-%{libmodulemd_v1_version}/modulemd-%{libmodulemd_v1_version}.tar.xz
BuildRequires: meson >= 0.47 BuildRequires: meson >= 0.47
BuildRequires: pkgconfig BuildRequires: pkgconfig
@ -18,27 +29,16 @@ BuildRequires: pkgconfig(gobject-2.0)
BuildRequires: pkgconfig(gobject-introspection-1.0) BuildRequires: pkgconfig(gobject-introspection-1.0)
BuildRequires: pkgconfig(yaml-0.1) BuildRequires: pkgconfig(yaml-0.1)
BuildRequires: pkgconfig(gtk-doc) BuildRequires: pkgconfig(gtk-doc)
BuildRequires: glib2-doc
BuildRequires: rpm-devel
BuildRequires: file-devel
BuildRequires: python3-devel BuildRequires: python3-devel
BuildRequires: python3-gobject-base BuildRequires: python3-gobject-base
%ifarch %{valgrind_arches} %ifarch %{valgrind_arches}
BuildRequires: valgrind BuildRequires: valgrind
%endif %endif
# Make sure we upgrade libmodulemd1 to match
Conflicts: libmodulemd1 < %{libmodulemd_v1_version}-%{release}
# Patches # Patches
Patch0001: 0001-Double-valgrind-timeout.patch
Patch0002: 0002-Parallelize-the-valgrind-tests.patch
Patch0003: 0003-Fix-transfer-type-for-Module.search_streams.patch
Patch0004: 0004-Extend-timeout-for-header-test.patch
#RHBZ #1763779- Merging defaults from third-party repositories
Patch0005: 0005-Add-test_data_path-env-var-for-Python-tests.patch
Patch0006: 0006-Add-ModuleIndexMerger.resolve_ext.patch
Patch0007: 0007-Rework-defaults-merging-logic-2x.patch
Patch0008: 0008-Rework-defaults-merging-logic-1x.patch
%description %description
@ -70,6 +70,7 @@ Development files for libmodulemd.
%package -n libmodulemd1 %package -n libmodulemd1
Summary: Compatibility package for libmodulemd 1.x Summary: Compatibility package for libmodulemd 1.x
Version: %{libmodulemd_v1_version} Version: %{libmodulemd_v1_version}
Release: %{libmodulemd_v1_release}
Obsoletes: libmodulemd < 2 Obsoletes: libmodulemd < 2
Provides: libmodulemd = %{libmodulemd_v1_version}-%{release} Provides: libmodulemd = %{libmodulemd_v1_version}-%{release}
Provides: libmodulemd%{?_isa} = %{libmodulemd_v1_version}-%{release} Provides: libmodulemd%{?_isa} = %{libmodulemd_v1_version}-%{release}
@ -81,6 +82,7 @@ Compatibility library for libmodulemd 1.x
%package -n libmodulemd1-devel %package -n libmodulemd1-devel
Summary: Compatibility development package for libmodulemd 1.x Summary: Compatibility development package for libmodulemd 1.x
Version: %{libmodulemd_v1_version} Version: %{libmodulemd_v1_version}
Release: %{libmodulemd_v1_release}
Requires: libmodulemd1%{?_isa} = %{libmodulemd_v1_version}-%{release} Requires: libmodulemd1%{?_isa} = %{libmodulemd_v1_version}-%{release}
Conflicts: %{name}-devel Conflicts: %{name}-devel
Obsoletes: libmodulemd-devel < 2 Obsoletes: libmodulemd-devel < 2
@ -106,26 +108,28 @@ Python 3 bindings for libmodulemd1
%prep %prep
%autosetup -p1 -n modulemd-%{libmodulemd_version} %setup -c
%setup -c -T -D -a 1
%build %build
# Build the v1 API first
pushd modulemd-%{libmodulemd_v1_version}
%define _vpath_builddir api1 %define _vpath_builddir api1
%meson -Ddeveloper_build=false -Dbuild_api_v1=true -Dbuild_api_v2=false %meson -Ddeveloper_build=false
%meson_build %meson_build
popd
# Build the v2 API
pushd modulemd-%{libmodulemd_v2_version}
%define _vpath_builddir api2 %define _vpath_builddir api2
%ifarch aarch64 %ifarch aarch64
# aarch64 builders have I/O issues that often causes the valgrind tests to # aarch64 builders have I/O issues that often causes the valgrind tests to
# time out. Skip them from the RPM build # time out. Skip them from the RPM build
export MMD_SKIP_VALGRIND=True export MMD_SKIP_VALGRIND=True
%endif %endif
%meson -Ddeveloper_build=false -Dbuild_api_v1=false -Dbuild_api_v2=true -Dwith_py3_overrides=true -Dwith_py2_overrides=false %meson -Ddeveloper_build=false -Dskip_formatters=true -Dwith_py3_overrides=true -Dwith_py2_overrides=false
%meson_build %meson_build
popd
%check %check
@ -140,27 +144,36 @@ export MMD_SKIP_VALGRIND=1
export MMD_SKIP_VALGRIND=1 export MMD_SKIP_VALGRIND=1
%endif %endif
pushd modulemd-%{libmodulemd_v1_version}
%define _vpath_builddir api1 %define _vpath_builddir api1
%{__meson} test -C %{_vpath_builddir} %{?_smp_mesonflags} --print-errorlogs -t 10 %{__meson} test -C %{_vpath_builddir} %{?_smp_mesonflags} --print-errorlogs -t 10
popd
pushd modulemd-%{libmodulemd_v2_version}
%define _vpath_builddir api2 %define _vpath_builddir api2
%{__meson} test -C %{_vpath_builddir} %{?_smp_mesonflags} --print-errorlogs -t 10 %{__meson} test -C %{_vpath_builddir} %{?_smp_mesonflags} --print-errorlogs -t 10
popd
%install %install
pushd modulemd-%{libmodulemd_v1_version}
%define _vpath_builddir api1 %define _vpath_builddir api1
%meson_install %meson_install
popd
pushd modulemd-%{libmodulemd_v2_version}
%define _vpath_builddir api2 %define _vpath_builddir api2
%meson_install %meson_install
popd
# Create a symlink for the libmodulemd1-devel package
ln -s libmodulemd.so.%{libmodulemd_v1_version} \ ln -s libmodulemd.so.%{libmodulemd_v1_version} \
%{buildroot}%{_libdir}/%{name}.so.compat %{buildroot}%{_libdir}/%{name}.so.compat
%files %files
%license COPYING %license modulemd-%{libmodulemd_v2_version}/COPYING
%doc README.md %doc modulemd-%{libmodulemd_v2_version}/README.md
%{_bindir}/modulemd-validator %{_bindir}/modulemd-validator
%{_libdir}/%{name}.so.2* %{_libdir}/%{name}.so.2*
%dir %{_libdir}/girepository-1.0 %dir %{_libdir}/girepository-1.0
@ -186,8 +199,8 @@ ln -s libmodulemd.so.%{libmodulemd_v1_version} \
%files -n libmodulemd1 %files -n libmodulemd1
%license COPYING %license modulemd-%{libmodulemd_v1_version}/COPYING
%doc README.md %doc modulemd-%{libmodulemd_v1_version}/README.md
%{_bindir}/modulemd-validator-v1 %{_bindir}/modulemd-validator-v1
%{_libdir}/%{name}.so.1* %{_libdir}/%{name}.so.1*
%dir %{_libdir}/girepository-1.0 %dir %{_libdir}/girepository-1.0
@ -206,9 +219,13 @@ ln -s libmodulemd.so.%{libmodulemd_v1_version} \
%changelog %changelog
* Tue Oct 29 2019 Stephen Gallagher <sgallagh@redhat.com> - 2.8.2-1
- Update to versions 2.8.2 and 1.8.16
- Resolves: rhbz#1752511
* Wed Oct 23 2019 Stephen Gallagher <sgallagh@redhat.com> - 2.5.0-4 * Wed Oct 23 2019 Stephen Gallagher <sgallagh@redhat.com> - 2.5.0-4
- Improve default merging logic when dealing with third-party repos - Improve default merging logic when dealing with third-party repos
- Resolves: rhbz#1763779 - Resolves: rhbz#1761805
* Wed May 29 2019 Stephen Gallagher <sgallagh@redhat.com> - 2.5.0-2 * Wed May 29 2019 Stephen Gallagher <sgallagh@redhat.com> - 2.5.0-2
- Fix memory corruption error using Module.search_rpms() from python - Fix memory corruption error using Module.search_rpms() from python