Hi all,
This is a proposal for extending the `dependency` attributes on
element declarations such that elements can extend the dependency
attributes and participate in parsing them.
This is a proposal aimed at reconciling a few topics which we've been
looking into recently.
* Plugins accessing private API[0]
In Chandan's announcement we underlined the importance of being
able to reduce redundancy in element declarations which stage
elements into different sysroots.
Any element which needs to parse an element name in it's
configuration and later use Element.search() to find that element
and treat it specially, is likely causing the user to enter
redundant information by requiring the user to specify the element
both as a dependency and also in the element configuration.
* Dependencies in a sysroot[1]
This is a proposal from Valentin from two years ago, which
underlines the usefulness of being able to stage elements in
multiple locations (which BuildStream does already, except that it
appears to not be an obvious thing for users).
This proposal would not solve Valentin's proposal by itself, but it
would provide a more convenient API for Valentin to go ahead with
extending the BuildElement with a feature to satisfy his
requirements.
The current way to implement this in BuildStream would be to add
new configuration to BuildElement allowing BuildElement to pick and
choose which dependencies it decides to stage at which paths.
After this proposal, it would allow the BuildElement abstract class
to add syntactic sugar to the dependency objects in the `depends`,
`build-depends` and `runtime-depends` lists, making the final user
facing feature a bit more user friendly.
* Replace Element.search() completely.
The Element.search() API has been broken[2] for a very long time,
as it does not support addressing elements across junction
boundaries.
I created this merge request[3] this weekend to address this, since
we now have a clearer story about project relative element paths,
however there are some problems with the patch.
Namely, in order to make Element.search() performant and avoid
redundantly reloading .bst files from the disk later on, we need to
cache a lot of data which we usually discard from the loader,
increasing our memory footprint by around 12%.
Considering that we've been wanting to provide a solution that is
more tightly coupled to the dependency lists, I think it is best if
we just let Element.search() die completely, as any utility it
provides can be replaced by this proposal.
Proposed format changes
=======================
The Dependency dictionary[4] would gain a single new `config`
attribute, which would be a dictionary who's semantics would be defined
by the owning element.
kind: foo
build-depends:
- filename: payload.bst
config:
#
# The plugin loaded as the `foo` kind can
# now be told anything specific about this
# dependency `payload.bst`.
#
frob-me: True
# Configuration that is parsed by the plugin
# loaded as the `foo` kind in this project
# is specified already on the toplevel `config`
# dictionary.
#
config:
some-config: "Yes please"
Proposed plugin API changes
===========================
The element would gain a new method for parsing dependency
configurations with a similar contract as Plugin.configure().
* This new method would be called after Plugin.configure() and before
Plugin.preflight()
* This new method would be given tuples of (Element, MappingNode) for
each direct dependency, regardless of whether it had specified a
`config` node (so the MappingNode is allowed to be `None` for some
entries).
This allows the plugin to make a judgement about dependencies which
no configuration was specified for.
For example: an element like x86Image might require 2 build
dependencies, one for the tooling to stage at `/` and another for
the payload to deploy at `%{build-root}`, so it could raise an
error if there is a third dependency specified which would be
ignored.
* This new method would be optional to implement, however it will be
mandatory if the user ever specifies a `config` dictionary for any
of the given plugin instance's dependencies.
This is to say that BuildStream core would take care of simply
raising a nice LoadError informing the user that `config` is an
invalid configuration for the said element, if the said element
does not implement any special parsing of dependency
configurations.
Example of Valentin's BuildElement proposal[1]
==============================================
I thought it would be good to include a small example of what the
BuildElement sysroot example might look like in YAML, based on the
`readline.bst` example in his original email:
depends:
- filename: glibc.bst
config:
sysroot: "%{sysroot}"
- filename: ncurses.bst
config:
sysroot: "%{sysroot}"
- filename: system-image.bst
type: build
- filename: sysroot-compiler.bst
type: build
In this example, the BuildElement class would implement
Element.configure_dependencies() in such a way as to collect a list of
all of the dependencies which are supposed to go in specific sysroots,
and stage those in those sysroots instead of `/`.
Implementation plan
===================
To implement this change I would go through 3 phases of implementation.
* Implement the new format and method
This would be done in the BuildStream core repository and
would introduce bare bones plugins in the `tests/` directory
for the purpose of testing the correct behaviors of the
feature.
At the same time, this would result in deprecation of
Element.search().
* Migrate existing plugins
In this phase, we would update the ScriptElement, base
class, the `script` convenience element, and any plugins
in `bst-plugins-experimental` which use `Element.search()`
to use the new `Element.configure_dependencies()` instead.
* Remove Element.search()
Once plugins have been migrated, we would remove
Element.search() entirely.
Any thoughts ? Please discuss :)
Cheers,
-Tristan
[0]:
https://lists.apache.org/thread.html/r057a6fa1ed275fcbc8d92972753bf32ce1e16ab3740580da69be3f3c%40%3Cdev.buildstream.apache.org%3E
[1]: https://mail.gnome.org/archives/buildstream-list/2018-August/msg00009.html
[2]: https://gitlab.com/BuildStream/buildstream/-/issues/931
[3]: https://gitlab.com/BuildStream/buildstream/-/merge_requests/1957
[4]:
https://docs.buildstream.build/master/format_declaring.html#expressing-dependencies