From 64fc74c73a162b61ff97e6b423563177e6e1a5cd Mon Sep 17 00:00:00 2001
From: Lubomír Sedlář <lsedlar@redhat.com>
Date: Nov 23 2021 14:29:26 +0000
Subject: Allow creating .composeinfo with subset of variants


---

diff --git a/bin/compose-create-legacy-composeinfo b/bin/compose-create-legacy-composeinfo
index f9d6982..9922008 100755
--- a/bin/compose-create-legacy-composeinfo
+++ b/bin/compose-create-legacy-composeinfo
@@ -20,7 +20,9 @@ def run(opts):
     compose = productmd.compose.Compose(opts.compose)
     target = opts.path or compose.compose_path
     with open(os.path.join(target, '.composeinfo'), 'w') as f:
-        write_legacy_composeinfo(compose.info, f, extra_addon_list=opts.addon)
+        write_legacy_composeinfo(
+            compose.info, f, extra_addon_list=opts.addon, variants=opts.variant
+        )
 
 
 def parse_variant_pair(val):
@@ -46,6 +48,12 @@ if __name__ == '__main__':
         type=parse_variant_pair,
         action="append",
     )
+    parser.add_argument(
+        "--variant",
+        metavar="VARIANT",
+        help="Include only VARIANT, can be specified multiple times.",
+        action="append",
+    )
 
     opts = parser.parse_args()
     run(opts)
diff --git a/compose_utils/legacy.py b/compose_utils/legacy.py
index e024033..4a48aa1 100644
--- a/compose_utils/legacy.py
+++ b/compose_utils/legacy.py
@@ -6,7 +6,7 @@ from itertools import chain
 from six.moves import configparser
 
 
-def write_legacy_composeinfo(ci, file, extra_addon_list=None):
+def write_legacy_composeinfo(ci, file, extra_addon_list=None, variants=None):
     """Write a legacy INI-style composeinfo data into `file`."""
     conf = configparser.ConfigParser(dict_type=SortedDict)
     _serialize_compose(conf, ci.compose)
@@ -16,7 +16,7 @@ def write_legacy_composeinfo(ci, file, extra_addon_list=None):
     extra_addons = defaultdict(set)
     for base, addon in extra_addon_list or []:
         extra_addons[base].add(addon)
-    _serialize_variants(conf, ci.variants, extra_addons=extra_addons)
+    _serialize_variants(conf, ci.variants, extra_addons=extra_addons, filter=variants)
     conf.write(file)
 
 
@@ -94,7 +94,7 @@ def _serialize_paths(conf, section, paths, arch):
         _set("debuginfo", paths.debug_repository, arch)
 
 
-def _serialize_variant(conf, variant, extra_addons):
+def _serialize_variant(conf, variant, extra_addons, filter=None):
     section = 'variant-%s' % variant.uid
     conf.add_section(section)
 
@@ -113,8 +113,9 @@ def _serialize_variant(conf, variant, extra_addons):
 
     children = set()
     for child in variant.variants.values():
-        _serialize_variant(conf, child, set())
-        children.add(child.uid)
+        if not filter or child in filter:
+            _serialize_variant(conf, child, set())
+            children.add(child.uid)
 
     children |= extra_addons
 
@@ -122,14 +123,18 @@ def _serialize_variant(conf, variant, extra_addons):
         conf.set(section, 'variants', ','.join(sorted(children)))
 
 
-def _serialize_variants(conf, variants, extra_addons):
-    ids = sorted(
-        set(variants.variants.keys()) - set(chain.from_iterable(extra_addons.values()))
-    )
-    conf.set('product', 'variants', ','.join(ids))
+def _serialize_variants(conf, variants, extra_addons, filter=None):
+    ids = set(variants.variants.keys()) - set(chain.from_iterable(extra_addons.values()))
+    if filter:
+        ids &= set(filter or [])
+    conf.set('product', 'variants', ','.join(sorted(ids)))
     for variant_id in sorted(variants.variants):
+        if filter and variant_id not in filter:
+            continue
         variant = variants.variants[variant_id]
-        _serialize_variant(conf, variant, extra_addons.get(variant_id, set()))
+        _serialize_variant(
+            conf, variant, extra_addons.get(variant_id, set()), filter=filter
+        )
 
 
 class SortedDict(dict):
diff --git a/doc/compose-create-legacy-composeinfo.1 b/doc/compose-create-legacy-composeinfo.1
index 1fda67c..15f2768 100644
--- a/doc/compose-create-legacy-composeinfo.1
+++ b/doc/compose-create-legacy-composeinfo.1
@@ -23,6 +23,9 @@ consumers expect the file to be.
 .BR \-\-addon = \fIBASE\fR:\fIADDON\fR
 Mark \fIADDON\fR variant as an addon to \fIBASE\fR, even though it may not be
 created as such. Can be specified multiple times.
+.TP
+.BR \-\-variant = \fIVARIANT\fR
+Include only \fIVARIANT\fR in the composeinfo. Can be specified multiple times.
 .SH BUGS
 Please report bugs at
 .br
diff --git a/tests/composes/DP-1.0-20160720.t.8/compose/.filtered.composeinfo b/tests/composes/DP-1.0-20160720.t.8/compose/.filtered.composeinfo
new file mode 100644
index 0000000..bbd3790
--- /dev/null
+++ b/tests/composes/DP-1.0-20160720.t.8/compose/.filtered.composeinfo
@@ -0,0 +1,104 @@
+[compose]
+date = 20160720
+id = DP-1.0-20160720.t.8
+respin = 8
+type = test
+
+[product]
+family = Dummy Product
+name = DP-1.0-20160720.t.8
+short = DP
+type = ga
+variants = Client,Server
+version = 1.0
+
+[variant-Client]
+arches = i386,x86_64
+id = Client
+name = Client
+type = variant
+uid = Client
+
+[variant-Client.i386]
+debug_dir = Client/i386/debug/tree
+debug_packages = Client/i386/debug/tree/Packages
+debug_repository = Client/i386/debug/tree
+debug_tree = Client/i386/debug/tree
+debuginfo = Client/i386/debug/tree
+iso_dir = Client/i386/iso
+isos = Client/i386/iso
+os_dir = Client/i386/os
+os_tree = Client/i386/os
+packages = Client/i386/os/Packages
+repository = Client/i386/os
+source_dir = Client/source/tree
+source_iso_dir = Client/source/iso
+source_isos = Client/source/iso
+source_packages = Client/source/tree/Packages
+source_repository = Client/source/tree
+source_tree = Client/source/tree
+
+[variant-Client.x86_64]
+debug_dir = Client/x86_64/debug/tree
+debug_packages = Client/x86_64/debug/tree/Packages
+debug_repository = Client/x86_64/debug/tree
+debug_tree = Client/x86_64/debug/tree
+debuginfo = Client/x86_64/debug/tree
+iso_dir = Client/x86_64/iso
+isos = Client/x86_64/iso
+os_dir = Client/x86_64/os
+os_tree = Client/x86_64/os
+packages = Client/x86_64/os/Packages
+repository = Client/x86_64/os
+source_dir = Client/source/tree
+source_iso_dir = Client/source/iso
+source_isos = Client/source/iso
+source_packages = Client/source/tree/Packages
+source_repository = Client/source/tree
+source_tree = Client/source/tree
+
+[variant-Server]
+arches = s390x,x86_64
+id = Server
+name = Server
+type = variant
+uid = Server
+
+[variant-Server.s390x]
+debug_dir = Server/s390x/debug/tree
+debug_packages = Server/s390x/debug/tree/Packages
+debug_repository = Server/s390x/debug/tree
+debug_tree = Server/s390x/debug/tree
+debuginfo = Server/s390x/debug/tree
+iso_dir = Server/s390x/iso
+isos = Server/s390x/iso
+os_dir = Server/s390x/os
+os_tree = Server/s390x/os
+packages = Server/s390x/os/Packages
+repository = Server/s390x/os
+source_dir = Server/source/tree
+source_iso_dir = Server/source/iso
+source_isos = Server/source/iso
+source_packages = Server/source/tree/Packages
+source_repository = Server/source/tree
+source_tree = Server/source/tree
+
+[variant-Server.x86_64]
+debug_dir = Server/x86_64/debug/tree
+debug_packages = Server/x86_64/debug/tree/Packages
+debug_repository = Server/x86_64/debug/tree
+debug_tree = Server/x86_64/debug/tree
+debuginfo = Server/x86_64/debug/tree
+iso_dir = Server/x86_64/iso
+isos = Server/x86_64/iso
+os_dir = Server/x86_64/os
+os_tree = Server/x86_64/os
+packages = Server/x86_64/os/Packages
+repository = Server/x86_64/os
+source_dir = Server/source/tree
+source_iso_dir = Server/source/iso
+source_isos = Server/source/iso
+source_packages = Server/source/tree/Packages
+source_repository = Server/source/tree
+source_tree = Server/source/tree
+
diff --git a/tests/test_legacy_composeinfo.py b/tests/test_legacy_composeinfo.py
index cb5d891..0be3369 100644
--- a/tests/test_legacy_composeinfo.py
+++ b/tests/test_legacy_composeinfo.py
@@ -39,6 +39,15 @@ class LegacyComposeInfoTest(unittest.TestCase):
             expected = f.read().split()
             self.assertEqual(output.getvalue().split(), expected)
 
+    def test_write_legacy_file_with_filter(self):
+        output = StringIO()
+        write_legacy_composeinfo(
+            self.compose.info, output, variants=["Client", "Server"]
+        )
+        with open(os.path.join(BASE_PATH, 'compose', get_expected(".filtered"))) as f:
+            expected = f.read().split()
+            self.assertEqual(output.getvalue().split(), expected)
+
     def test_write_legacy_file_no_paths(self):
         output = StringIO()
         # Keep only Server variant and remove all paths for server

