From 99abc1373d5c6a85eb1a6ca6eaade0ee3c27ec18 Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Tue, 12 Apr 2022 23:40:22 +0200 Subject: [PATCH] inputs: support array of objects references This extends the possible ways of passing references to inputs. The current ways possible are: 1) "plain references", an array of strings: ["ref1", "ref2", ...] 2) "object references", a mapping of keys to objects: {"ref1": { }, "ref2": { }, ...} This patch adds a new way: 3) "array of object references": [{"id": "ref1", "options": { ... }}, {"id": ... }, ] While osbuild promises to preserves the order for "object references" not all JSON serialization libraries preserve the order since the JSON specification does leave this up to the implementation. The new "array of object references" thus allows for specifying the references together with reference specific options and this in a specific order. Additionally this paves the way for specifying the same input twice, e.g. in the case of the `org.osbuild.files` input where a pipeline could then be specified twice with different files. This needs core rework though, since internally we use dictionaries right now. --- inputs/org.osbuild.containers | 44 ++++++++++++++++++++++++++++-- inputs/org.osbuild.files | 40 ++++++++++++++++++++++++++- inputs/org.osbuild.ostree | 18 ++++++++++++ inputs/org.osbuild.ostree.checkout | 18 ++++++++++++ inputs/org.osbuild.tree | 19 +++++++++++++ osbuild/formats/v2.py | 9 +++++- schemas/osbuild2.json | 16 ++++++++++- test/mod/test_fmt_v2.py | 6 ++++ 8 files changed, 165 insertions(+), 5 deletions(-) diff --git a/inputs/org.osbuild.containers b/inputs/org.osbuild.containers index a787f42b..7d2f5562 100755 --- a/inputs/org.osbuild.containers +++ b/inputs/org.osbuild.containers @@ -46,6 +46,23 @@ SCHEMA = r""" } } }, + "source-array-ref": { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "additionalProperties": false, + "required": ["id"], + "properties": { + "id": { + "type": "string" + }, + "options": { + "$ref": "#/definitions/source-options" + } + } + } + }, "source-origin": { "type": "string", "description": "When the origin of the input is a source", @@ -72,6 +89,23 @@ SCHEMA = r""" } } }, + "pipeline-array-ref": { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "additionalProperties": false, + "required": ["id"], + "properties": { + "id": { + "type": "string" + }, + "options": { + "$ref": "#/definitions/pipeline-options" + } + } + } + }, "pipeline-origin": { "type": "string", "description": "When the origin of the input is a pipeline", @@ -93,7 +127,10 @@ SCHEMA = r""" }, "references": { "description": "Container image id", - "$ref": "#/definitions/source-object-ref" + "oneOf": [ + {"$ref": "#/definitions/source-array-ref"}, + {"$ref": "#/definitions/source-object-ref"} + ] } } }, @@ -110,7 +147,10 @@ SCHEMA = r""" }, "references": { "description": "References to pipelines", - "$ref": "#/definitions/pipeline-object-ref" + "oneOf": [ + {"$ref": "#/definitions/pipeline-array-ref"}, + {"$ref": "#/definitions/pipeline-object-ref"} + ] } } } diff --git a/inputs/org.osbuild.files b/inputs/org.osbuild.files index 2cad3876..a088eac4 100755 --- a/inputs/org.osbuild.files +++ b/inputs/org.osbuild.files @@ -62,6 +62,23 @@ SCHEMA = r""" } } }, + "source-array-ref": { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "additionalProperties": false, + "required": ["id"], + "properties": { + "id": { + "type": "string" + }, + "options": { + "$ref": "#/definitions/source-options" + } + } + } + }, "source-origin": { "type": "string", "description": "When the origin of the input is a source", @@ -89,6 +106,23 @@ SCHEMA = r""" } } }, + "pipeline-array-ref": { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "additionalProperties": false, + "required": ["id"], + "properties": { + "id": { + "type": "string" + }, + "options": { + "$ref": "#/definitions/pipeline-options" + } + } + } + }, "pipeline-origin": { "type": "string", "description": "When the origin of the input is a pipeline", @@ -112,6 +146,7 @@ SCHEMA = r""" "description": "Checksums of files to use as files input", "oneOf": [ {"$ref": "#/definitions/plain-ref"}, + {"$ref": "#/definitions/source-array-ref"}, {"$ref": "#/definitions/source-object-ref"} ] } @@ -130,7 +165,10 @@ SCHEMA = r""" }, "references": { "description": "References to pipelines", - "$ref": "#/definitions/pipeline-object-ref" + "oneOf": [ + {"$ref": "#/definitions/pipeline-array-ref"}, + {"$ref": "#/definitions/pipeline-object-ref"} + ] } } } diff --git a/inputs/org.osbuild.ostree b/inputs/org.osbuild.ostree index 5af5fe05..53983abf 100755 --- a/inputs/org.osbuild.ostree +++ b/inputs/org.osbuild.ostree @@ -61,6 +61,24 @@ SCHEMA = """ "$ref": "#/definitions/options" } } + }, { + "type": "array", + "additionalItems": false, + "minItems": 1, + "maxItems": 1, + "items": [{ + "type": "object", + "additionalProperties": false, + "required": ["id"], + "properties": { + "id": { + "type": "string" + }, + "options": { + "$ref": "#/definitions/options" + } + } + }] }] } } diff --git a/inputs/org.osbuild.ostree.checkout b/inputs/org.osbuild.ostree.checkout index e6f7b269..843afb48 100755 --- a/inputs/org.osbuild.ostree.checkout +++ b/inputs/org.osbuild.ostree.checkout @@ -45,6 +45,24 @@ SCHEMA = """ "additionalProperties": false } } + }, { + "type": "array", + "additionalItems": false, + "minItems": 1, + "items": [{ + "type": "object", + "additionalProperties": false, + "required": ["id"], + "properties": { + "id": { + "type": "string" + }, + "options": { + "type": "object", + "additionalProperties": false + } + } + }] }] } } diff --git a/inputs/org.osbuild.tree b/inputs/org.osbuild.tree index b1cef0e1..be7945d0 100755 --- a/inputs/org.osbuild.tree +++ b/inputs/org.osbuild.tree @@ -46,6 +46,25 @@ SCHEMA = """ }, "minProperties": 1, "maxProperties": 1 + }, { + "type": "array", + "additionalItems": false, + "minItems": 1, + "maxItems": 1, + "items": [{ + "type": "object", + "additionalProperties": false, + "required": ["id"], + "properties": { + "id": { + "type": "string" + }, + "options": { + "type": "object", + "additionalProperties": false + } + } + }] }] } } diff --git a/osbuild/formats/v2.py b/osbuild/formats/v2.py index 824a19f0..a90975e7 100644 --- a/osbuild/formats/v2.py +++ b/osbuild/formats/v2.py @@ -248,7 +248,14 @@ def load_input(name: str, description: Dict, index: Index, stage: Stage, manifes refs = description.get("references", {}) if isinstance(refs, list): - refs = {r: {} for r in refs} + def make_ref(ref): + if isinstance(ref, str): + return ref, {} + if isinstance(ref, dict): + return ref.get("id"), ref.get("options", {}) + raise ValueError(f"Invalid reference: {ref}") + + refs = dict(make_ref(ref) for ref in refs) if origin == "org.osbuild.pipeline": resolved = {} diff --git a/schemas/osbuild2.json b/schemas/osbuild2.json index d9f0d535..d2b85eac 100644 --- a/schemas/osbuild2.json +++ b/schemas/osbuild2.json @@ -114,9 +114,23 @@ { "type": "array", "items": { "type": "string" } - },{ + }, { "type": "object", "additionalProperties": true + }, { + "type": "array", + "items": { + "type": "object", + "required": ["id"], + "additionalProperties": false, + "properties": { + "id": { "type": "string" }, + "options": { + "type": "object", + "additionalProperties": true + } + } + } } ] }, diff --git a/test/mod/test_fmt_v2.py b/test/mod/test_fmt_v2.py index cf050194..b582cb54 100644 --- a/test/mod/test_fmt_v2.py +++ b/test/mod/test_fmt_v2.py @@ -439,3 +439,9 @@ class TestFormatV2(unittest.TestCase): } self.check_input_references(desc) + + # check references passed as array of objects + inputs["references"] = [ + {"id": k, "options": {}} for k in refs + ] + self.check_input_references(desc)