paketo-buildpacks / libjvm

A library and helper applications that form the basis for building the different Paketo-style JVM-providing buildpacks
Apache License 2.0
18 stars 19 forks source link

Allow JVM version selection by other buildpacks #365

Closed Infra-Red closed 5 months ago

Infra-Red commented 5 months ago

Describe the Enhancement

I would like to add an option where other buildpacks can request a specific version of JVM during their detection phase. An example of such behavior will be the go-mod-vendor buildpack which will add a Go version to detect the result if go.mod file is present in the project folder: https://github.com/paketo-buildpacks/go-mod-vendor/blob/5751b3509020a6e2c98db91a0c9e3b09c9e30f63/detect.go#L36-L49.

Currently, there are three options:

and the buildpack will use the default version if none of these is satisfied. With my proposed change there will be another option that will check if the JVM version was already specified by another buildpack in BuildPlanRequirement.

Possible Solution

I think updating GetJVMVersion method will be enough, but I didn't dive deep enough into the libjvm code yet. I'm open to suggestions if this feature request is something that the team is willing to support.

Motivation

In my scenario, I have a custom non-paketo buildpack that requires jre in the detection phase and I'm using adoptium buildpack to provide JRE in the launch environment. My buildpack may require JRE 11 or JRE 17 depending on how old is an application and it would simplify workflow if can specify which JVM version to request from my buildpack.

dmikusa commented 5 months ago

This is something that has come up before. I did a quick look and couldn't find an issue, so it may have been a Slack conversation or I may have just missed it. Anyway, I believe the gist of that previous conversation is that we are not doing this presently because it complicates the buildpacks (buildplans complexity increases very fast) and Java version selection logic. As with all things, if there's enough interest and a strong enough use case then we could implement it.

For your particular scenario, I would suggest you set BP_JVM_VERSION. To make this work, your buildpack needs to run before the JVM provider buildpack, so it would need to go toward the beginning. If that's not possible, because it needs to run after for some other reason, then I would suggest you split and have two buildpacks. One before and one after. The buildpack before sets the JVM version, the buildpack after can then do whatever post-processing you need to do.

Infra-Red commented 5 months ago

Thanks for the suggestion @dmikusa! To clarify, do you mean that I can simply os.Setenv("BP_JVM_VERSION", "20") in the detect script of the buildpack that is running before the JVM provider buildpack. Another option I can think of is to set it in the build environment, but afaik it's not available for the subsequent buildpacks.

dmikusa commented 5 months ago

os.Setenv would only be applicable during the current buildpack, but buildpacks provide a way to set env variables for other buildpacks at build time and at runtime.

The spec details this here -> https://github.com/buildpacks/spec/blob/main/buildpack.md#provided-by-the-buildpacks

In libcnb, it's exposed through the Layer, you can write build, launch (i.e. runtime) or shared (i.e. both). It will take care of writing the files and doing what the buildpack needs. Example.

In this case, you'd want to set it as a build env variable. The lifecycle will then apply that env variable for all subsequent buildpacks so it'll be set when the rest of the buildpacks run, which is what you want here. All the libjvm based buildpacks look at this env variable at build time and use that to determine what version to install.

Infra-Red commented 5 months ago

I was able to work around it by setting BP_JVM_VERSION in the build-level environment variables of my custom buildpack. Thanks again for your help @dmikusa!