Message ID | 20220817131023.4093773-2-alex@linutronix.de |
---|---|
State | Accepted, archived |
Commit | 72740b5dd635579e373b4bfe6ccacfe6a02aa998 |
Headers | show |
Series | [1/5] bitbake-layers: add a command to save the active build configuration as a template into a layer | expand |
On Wed, 2022-08-17 at 15:10 +0200, Alexander Kanavin wrote: > From: Joshua Watt <JPEWhacker@gmail.com> > > Defines a common schema for layer setup that can be consumed by tools to > know how to fetch and assemble layers for end users. Also includes an > example of the layer setup that constructs poky/meta-intel/imaginary product layer > for reference. > > The schema can be used to validate a layer setup file with the commands: > > $ python3 -m pip install jsonschema > $ jsonschema -i meta/files/layers.example.json meta/files/layers.schema.json > > Signed-off-by: Joshua Watt <JPEWhacker@gmail.com> > > Alex: I made the following modifications to Joshua's original commit: > > - moved the files from meta/lib to meta/files > > - the example json showcases a multi-repo, multi-layer setup with additional > configurations and machines, instead of just poky - closer to a typical product > > - added oe-selftest that validates the example json against the schema using python3-jsonschema-native > > - the schema is modified so that: > > -- all lists (sources, layers, remotes) are replaced by objects keyed by 'name' properties of the list items. > This allows using them as dicts inside Python, and makes the json more compact and readable. > > -- added 'contains_this_file' property to source object > > -- added 'buildconfigs', 'machines' and 'distros' properties to layer objects. > > -- replaced 'remote' property with a 'oneOf' definition for git with a specific > 'git-remote' property. 'oneOf' is problematic when schema validation fails: > the diagnostic is only that none of oneOf variants matched, which is too non-specific. > > -- added 'describe' property to 'git-remote' object. > > -- removed description property for a layer source: it is not clear how to add that > when auto-generating the json I finally got some time to think about this a little bit more. One thing that concerns me a little is that this mixes two things, layer setup (as in repos) and configuration. I'm nervous about json config which effectively has to duplicate the list of machines/distros in layers. Where is the distro/machine data used? Are these the only config options people will want to add or will we have others? init system? libc? Or feature information about which configurations are expected to work? I worry this is a magnet for future feature creep and duplication of information. I can see where the buildconfigs are used but again, does the json file need to encode those or could you determine them by inspection of the layers once setup? I'm still worried about bolting a format directly into one of our core tools as it effectively means it is a definitive standard. We do probably need one but I'm not convinced this is quite right, perhaps because of the above reason. Not 100% sure but something doesn't feel quite right. Also, if there is new version of this series, could you squash in these copyright/license tweaks please: https://git.yoctoproject.org/poky/commit/?h=master-next&id=45b396298c1dd638bb702f5251b4a663f07978ca Cheers, Richard
On Wed, 17 Aug 2022 at 22:52, Richard Purdie <richard.purdie@linuxfoundation.org> wrote: > One thing that concerns me a little is that this mixes two things, > layer setup (as in repos) and configuration. I'm nervous about json > config which effectively has to duplicate the list of machines/distros > in layers. > > Where is the distro/machine data used? The use case I was thinking of is doing something useful with this information *before* doing actual checkout. I would even appreciate knowing in advance - maybe even by just looking at the json through gitweb ui - which machines, distros and config templates I would be getting, and from which layers. Also the proposed oe-setup tool could do useful things with this information, if it operates from the json definitions in the same format. You can discover and supply all needed information up front, and oe-setup will land you in a bitbake session. Without it, you have to first do the layer setup, then the configuration discovery, then the configuration setup, as separate commands - I'd say that would be an inferior experience for the users. > Are these the only config options people will want to add or will we > have others? init system? libc? Or feature information about which > configurations are expected to work? I worry this is a magnet for > future feature creep and duplication of information. These are not the same, as machines and distros are specifically defined in layers as .conf files in pre-determined locations. Other things are defined as variables in files, and aren't as easily discoverable by code. I only want to allow programmatically discoverable options (that are guaranteed to be in lockstep with the layer revision) in the json; no one should ever write or modify the json by hand. > I can see where the buildconfigs are used but again, does the json file > need to encode those or could you determine them by inspection of the > layers once setup? In addition to the above point (knowing them in advance is useful), there is no fixed location for these in layers. You could perhaps walk the layer trees, but I'd rather place the info in the json. > Also, if there is new version of this series, could you squash in these > copyright/license tweaks please: > > https://git.yoctoproject.org/poky/commit/?h=master-next&id=45b396298c1dd638bb702f5251b4a663f07978ca This is the easy part :-) Hope the above clarifies a bit what went on in my head when I was writing the code. Alex
On Wed, 17 Aug 2022 at 22:52, Richard Purdie <richard.purdie@linuxfoundation.org> wrote: > I'm still worried about bolting a format directly into one of our core > tools as it effectively means it is a definitive standard. We do > probably need one but I'm not convinced this is quite right, perhaps > because of the above reason. Not 100% sure but something doesn't feel > quite right. This part can perhaps be addressed by the venerable 'adding an abstraction layer', in the shape of config format generator plugins. I can supply the native json plugin, others can add kas, repo, or whatever else they find useful. Also, the json is versioned and almost nothing in it is required. If some ideas don't work out, or are found to cause problems, there are ways to transition out of problematic bits - perhaps even as simple as dropping the bad ideas from the generator, or the setup script, without modifying the schema. We do need a starting point though. Alex
On Wed, 2022-08-17 at 23:36 +0200, Alexander Kanavin wrote: > On Wed, 17 Aug 2022 at 22:52, Richard Purdie > <richard.purdie@linuxfoundation.org> wrote: > > One thing that concerns me a little is that this mixes two things, > > layer setup (as in repos) and configuration. I'm nervous about json > > config which effectively has to duplicate the list of machines/distros > > in layers. > > > > Where is the distro/machine data used? > > The use case I was thinking of is doing something useful with this > information *before* doing actual checkout. I would even appreciate > knowing in advance - maybe even by just looking at the json through > gitweb ui - which machines, distros and config templates I would be > getting, and from which layers. The trouble is that others already went a different direction with this which is why we have layer index and the concept of local layer indexes as well we the ability for bblayers to talk to such indexes if I'm remembering correctly. An advantage it has is that it does parse the layers so it can cache other information too. My worry is that you have two copies of this information, one in the json and one in the metadata and effectively by that fact, one of them will be wrong. You could report it to the user with a directory listing of the remote repo via git. > Also the proposed oe-setup tool could > do useful things with this information, if it operates from the json > definitions in the same format. You can discover and supply all needed > information up front, and oe-setup will land you in a bitbake session. > Without it, you have to first do the layer setup, then the > configuration discovery, then the configuration setup, as separate > commands - I'd say that would be an inferior experience for the users. I think you can get a lot of this information relatively easily and possibly without a clone, via a layer index or probably through a remote git command too. > > Are these the only config options people will want to add or will we > > have others? init system? libc? Or feature information about which > > configurations are expected to work? I worry this is a magnet for > > future feature creep and duplication of information. > > These are not the same, as machines and distros are specifically > defined in layers as .conf files in pre-determined locations. Other > things are defined as variables in files, and aren't as easily > discoverable by code. I only want to allow programmatically > discoverable options (that are guaranteed to be in lockstep with the > layer revision) in the json; no one should ever write or modify the > json by hand. I'm not sure that will scale for what users want then (which I suspect is why we ended up with the layer index instead). > > I can see where the buildconfigs are used but again, does the json file > > need to encode those or could you determine them by inspection of the > > layers once setup? > > In addition to the above point (knowing them in advance is useful), > there is no fixed location for these in layers. You could perhaps walk > the layer trees, but I'd rather place the info in the json. I have wondered if we should define one. I kind of have a plan in mind to turn the majority of the autobuilder configurations into config files somewhere in OE-Core to make it easier for people to reproduce autobuilder configs too, which may be an interesting example of that. > > Also, if there is new version of this series, could you squash in these > > copyright/license tweaks please: > > > > https://git.yoctoproject.org/poky/commit/?h=master-next&id=45b396298c1dd638bb702f5251b4a663f07978ca > > This is the easy part :-) Hope the above clarifies a bit what went on > in my head when I was writing the code. It does, thanks. I'm just not sure we're quite in the right place with things. I know in your other reply you say we have to start somewhere and we can change things. I also know the screaming if we try and remove something later... Cheers, Richard
On Thu, 18 Aug 2022 at 00:27, Richard Purdie <richard.purdie@linuxfoundation.org> wrote: > It does, thanks. I'm just not sure we're quite in the right place with > things. I know in your other reply you say we have to start somewhere > and we can change things. I also know the screaming if we try and > remove something later... Right, I'm going to make the following changes: - machine/distro/config-template stuff gets dropped from the schema and tools - I am convinced now that it can be discovered through other means :-) - config template location gets standardized (perhaps in conf/templates/), default template in oe-core moves to conf/templates/default/ - add a plugin abstraction for the layer setup writers, move the json writer to a plugin Anything else? Alex
On Thu, 2022-08-18 at 10:24 +0200, Alexander Kanavin wrote: > On Thu, 18 Aug 2022 at 00:27, Richard Purdie > <richard.purdie@linuxfoundation.org> wrote: > > > It does, thanks. I'm just not sure we're quite in the right place with > > things. I know in your other reply you say we have to start somewhere > > and we can change things. I also know the screaming if we try and > > remove something later... > > Right, I'm going to make the following changes: > - machine/distro/config-template stuff gets dropped from the schema > and tools - I am convinced now that it can be discovered through other > means :-) > - config template location gets standardized (perhaps in > conf/templates/), default template in oe-core moves to > conf/templates/default/ > - add a plugin abstraction for the layer setup writers, move the json > writer to a plugin > > Anything else? I think that is a good plan and lets us move forward. If it turns out we need to extend the json, we can. Incrementally extending if/as needed is the safer path forward. That would just leave the details of the template layout. I think what you have above is probably fine. I'm just wondering how it fits with something else I've been worrying about, e.g. how to add config fragments to be used on the autobuilder. The intent is the user could add something like: require conf/yocto-autobuilder/x32.inc or require conf/yocto-autobuilder/multilib-mipsn32.inc and similar to their local.conf and more easily replicate configurations. With those, I could add to OE-Core or meta-yocto. I'm leaning towards core, just so people can see the testing configs more easily but I know people don't like yocto mentions in core and whether or not it is too higher a level in conf, not sure. Anyway, I think it is tangential to what you're working on which is good and stops me worrying. I left this in here just to write it out somewhere. I would like to see if we can switch the eSDK to use the json format btw. I suspect that may be one of your next steps? :) Cheers, Richard
On Thu, 18 Aug 2022 at 11:27, Richard Purdie <richard.purdie@linuxfoundation.org> wrote: > The intent is the user could add something like: > > require conf/yocto-autobuilder/x32.inc > > or > > require conf/yocto-autobuilder/multilib-mipsn32.inc > > and similar to their local.conf and more easily replicate > configurations. This could be a subset of a broader feature, one that allows adding and removing pre-canned 'config fragments' to local.conf. The proposal is to have such fragments live in meta-somelayer/conf/fragments/path/to/some/fragment (I think allowing multiple levels is beneficial here), and each fragment would start with a comment explaining what it does followed by the actual settings. Then adding fragments can be done by appending them to local.conf, and removing by looking for markers in local.conf and editing it out, which probably could use a helper tool/subcommand. Layers could also declare 'non-optional' fragments which get included automatically by the fact of including the layer into the build, which means layer.conf can go back to being short and sweet and to the point. Thoughts? > I would like to see if we can switch the eSDK to use the json format > btw. I suspect that may be one of your next steps? :) I don't think I understand this, can you explain? Alex
Wind River already has a mechanism to do something like this, called templates. https://github.com/WindRiver-Labs/wr-template/tree/WRLINUX_10_21_BASE Each template can have (optionally): # README - template README file # require - list of other templates required for this one # template.conf - template configuration fragment # image.inc - image fragment # bsp-pkgs.conf - BSP specific configuration fragment # bsp-pkgs.inc - BSP specific image fragment # The 'bsp-pkgs' files can only be in a template in a layer that provides a # specific conf/machine/${MACHINE}.conf file and layers it may contain, # otherwise they will be ignored I'm not saying what is implemented is a perfect solution, but it made a 'configuration fragment' approach to system configuration much easier when I worked with it. (For examples see: https://github.com/WindRiver-Labs/wrlinux/tree/WRLINUX_10_21_BASE/templates/feature) You could do things (in your local.conf, or machine.conf or distro.conf) like: WRTEMPLATE += "dpdk" This would add the dpdk recipes to your image and also configure the kernel for dpdk. https://github.com/WindRiver-Labs/wrlinux/tree/WRLINUX_10_21_BASE/templates/feature/dpdk --Mark On 9/1/22 10:29 AM, Alexander Kanavin wrote: > On Thu, 18 Aug 2022 at 11:27, Richard Purdie > <richard.purdie@linuxfoundation.org> wrote: >> The intent is the user could add something like: >> >> require conf/yocto-autobuilder/x32.inc >> >> or >> >> require conf/yocto-autobuilder/multilib-mipsn32.inc >> >> and similar to their local.conf and more easily replicate >> configurations. > > This could be a subset of a broader feature, one that allows adding > and removing pre-canned 'config fragments' to local.conf. The proposal > is to have such fragments live in > meta-somelayer/conf/fragments/path/to/some/fragment (I think allowing > multiple levels is beneficial here), and each fragment would start > with a comment explaining what it does followed by the actual > settings. > > Then adding fragments can be done by appending them to local.conf, and > removing by looking for markers in local.conf and editing it out, > which probably could use a helper tool/subcommand. > > Layers could also declare 'non-optional' fragments which get included > automatically by the fact of including the layer into the build, which > means layer.conf can go back to being short and sweet and to the > point. > > Thoughts? > >> I would like to see if we can switch the eSDK to use the json format >> btw. I suspect that may be one of your next steps? :) > > I don't think I understand this, can you explain? > > Alex > > > > -=-=-=-=-=-=-=-=-=-=-=- > Links: You receive all messages sent to this group. > View/Reply Online (#1627): https://lists.openembedded.org/g/openembedded-architecture/message/1627 > Mute This Topic: https://lists.openembedded.org/mt/93398201/3616948 > Group Owner: openembedded-architecture+owner@lists.openembedded.org > Unsubscribe: https://lists.openembedded.org/g/openembedded-architecture/unsub [mark.hatle@kernel.crashing.org] > -=-=-=-=-=-=-=-=-=-=-=- >
diff --git a/meta/files/layers.example.json b/meta/files/layers.example.json new file mode 100644 index 0000000000..b6e35c615d --- /dev/null +++ b/meta/files/layers.example.json @@ -0,0 +1,115 @@ +{ + "sources": { + "meta-alex": { + "contains_this_file": true, + "git-remote": { + "branch": "master", + "describe": "", + "remotes": { + "remote-alex": { + "uri": "https://github.com/kanavin/meta-alex" + } + }, + "rev": "05b25605fb8b2399e4706d7323828676bf0da0b5" + }, + "layers": { + "meta-alex": { + "buildconfigs": { + "conf/templates/configuration-gadget": {}, + "conf/templates/configuration-gizmo": {} + }, + "subpath": "" + } + }, + "path": "meta-alex" + }, + "meta-intel": { + "git-remote": { + "branch": "master", + "describe": "15.0-hardknott-3.3-310-g0a96edae", + "remotes": { + "origin": { + "uri": "git://git.yoctoproject.org/meta-intel" + } + }, + "rev": "0a96edae609a3f48befac36af82cf1eed6786b4a" + }, + "layers": { + "meta-intel": { + "machines": { + "intel-core2-32": {}, + "intel-corei7-64": {}, + "intel-skylake-64": {} + }, + "subpath": "" + } + }, + "path": "meta-intel" + }, + "poky": { + "git-remote": { + "branch": "akanavin/setup-layers", + "describe": "4.1_M1-374-g9dda719b2a", + "remotes": { + "origin": { + "uri": "git://git.yoctoproject.org/poky" + }, + "poky-contrib": { + "uri": "ssh://git@push.yoctoproject.org/poky-contrib" + } + }, + "rev": "9dda719b2a4727a4d43a6ab8d9e23f8ca68790ec" + }, + "layers": { + "meta": { + "distros": { + "defaultsetup": {} + }, + "machines": { + "qemuarm": {}, + "qemuarm64": {}, + "qemuarmv5": {}, + "qemumips": {}, + "qemumips64": {}, + "qemuppc": {}, + "qemuppc64": {}, + "qemuriscv32": {}, + "qemuriscv64": {}, + "qemux86": {}, + "qemux86-64": {} + }, + "subpath": "meta" + }, + "meta-poky": { + "buildconfigs": { + "conf": {} + }, + "distros": { + "poky": {}, + "poky-altcfg": {}, + "poky-bleeding": {}, + "poky-tiny": {} + }, + "subpath": "meta-poky" + }, + "meta-selftest": { + "machines": { + "qemux86copy": {} + }, + "subpath": "meta-selftest" + }, + "meta-yocto-bsp": { + "machines": { + "beaglebone-yocto": {}, + "edgerouter": {}, + "genericx86": {}, + "genericx86-64": {} + }, + "subpath": "meta-yocto-bsp" + } + }, + "path": "poky" + } + }, + "version": "1.0" +} diff --git a/meta/files/layers.schema.json b/meta/files/layers.schema.json new file mode 100644 index 0000000000..2603fae8f7 --- /dev/null +++ b/meta/files/layers.schema.json @@ -0,0 +1,121 @@ +{ + "description": "OpenEmbedder Layer Setup Manifest", + "type": "object", + "additionalProperties": false, + "required": [ + "version" + ], + "properties": { + "version": { + "description": "The version of this document; currently '1.0'", + "enum": ["1.0"] + }, + "sources": { + "description": "The dict of layer sources", + "type": "object", + "patternProperties": { ".*" : { + "type": "object", + "description": "The upstream source from which a set of layers may be fetched", + "additionalProperties": false, + "required": [ + "path" + ], + "properties": { + "path": { + "description": "The path where this layer source will be placed when fetching", + "type": "string" + }, + "contains_this_file": { + "description": "Whether the directory with the layer source also contains this json description. Tools may want to skip the checkout of the source then.", + "type": "boolean" + }, + "layers": { + "description": "The dict of layers to be used from this upstream source", + "type": "object", + "patternProperties": { ".*" : { + "description": "A layer from the upstream source", + "type": "object", + "additionalProperties": false, + "properties": { + "subpath": { + "description": "The subpath (relative to the source root) for this layer. Omit if the source root is the layer path", + "type": "string" + }, + "buildconfigs": { + "description": "A dict of template build configurations in the layer, keyed by relative path to the layer root", + "type": "object", + "patternProperties": { ".*" : { + "description": "Properties of a build confuguration template", + "type": "object", + "additionalProperties": false, + "properties":{} + }} + }, + "machines": { + "description": "A dict of machine definitions in the layer", + "type": "object", + "patternProperties": { ".*" : { + "description": "Properties of a machine definition", + "type": "object", + "additionalProperties": false, + "properties":{} + }} + }, + "distros": { + "description": "A dict of distro definitions in the layer", + "type": "object", + "patternProperties": { ".*" : { + "description": "Properties of a distro definition", + "type": "object", + "additionalProperties": false, + "properties":{} + }} + } + } + }} + }, + "git-remote": { + "description": "A remote git source from which to fetch", + "type": "object", + "additionalProperties": false, + "required": [ + "rev" + ], + "properties": { + "branch": { + "description": "The git branch to fetch (optional)", + "type": "string" + }, + "rev": { + "description": "The git revision to checkout", + "type": "string" + }, + "describe": { + "description": "The output of 'git describe' (human readable description of the revision using tags in revision history).", + "type": "string" + }, + "remotes": { + "description": "The dict of git remotes to add to this repository", + "type": "object", + "patternProperties": { ".*" : { + "description": "A git remote", + "type": "object", + "addtionalProperties": false, + "required": [ + "uri" + ], + "properties": { + "uri": { + "description": "The URI for the remote", + "type": "string" + } + } + }} + } + } + } + } + } + }} + } +} diff --git a/meta/lib/oeqa/selftest/cases/bblayers.py b/meta/lib/oeqa/selftest/cases/bblayers.py index 549abe7d10..c753a7b795 100644 --- a/meta/lib/oeqa/selftest/cases/bblayers.py +++ b/meta/lib/oeqa/selftest/cases/bblayers.py @@ -8,12 +8,16 @@ import os import re import oeqa.utils.ftools as ftools -from oeqa.utils.commands import runCmd, get_bb_var, get_bb_vars +from oeqa.utils.commands import runCmd, get_bb_var, get_bb_vars, bitbake from oeqa.selftest.case import OESelftestTestCase class BitbakeLayers(OESelftestTestCase): + def setUpLocal(self): + bitbake("python3-jsonschema-native") + bitbake("-c addto_recipe_sysroot python3-jsonschema-native") + def test_bitbakelayers_layerindexshowdepends(self): result = runCmd('bitbake-layers layerindex-show-depends meta-poky') find_in_contents = re.search("openembedded-core", result.output) @@ -128,3 +132,13 @@ class BitbakeLayers(OESelftestTestCase): self.assertTrue(os.path.isfile(recipe_file), msg = "Can't find recipe file for %s" % recipe) return os.path.basename(recipe_file) + + def validate_layersjson(self, json): + python = os.path.join(get_bb_var('STAGING_BINDIR', 'python3-jsonschema-native'), 'nativepython3') + jsonvalidator = os.path.join(get_bb_var('STAGING_BINDIR', 'python3-jsonschema-native'), 'jsonschema') + jsonschema = os.path.join(get_bb_var('COREBASE'), 'meta/files/layers.schema.json') + result = runCmd("{} {} -i {} {}".format(python, jsonvalidator, json, jsonschema)) + + def test_validate_examplelayersjson(self): + json = os.path.join(get_bb_var('COREBASE'), "meta/files/layers.example.json") + self.validate_layersjson(json)