-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow making an executable-jar image by only providing an executable JAR #265
Allow making an executable-jar image by only providing an executable JAR #265
Conversation
Can you expand more on the use case here? I saw you other issue, but it's not clear to me exactly what you're trying to do and why. Can you provide some more details? A working reproduction including code/steps to produce a JAR file that fits what you're trying to do would be helpful. |
Let's say we have build a fat JAR from our project: We can apply the buildpack to create an image that runs the jar using:
However, this has the downside that the JAR is exploded in the image, which can cause some side-effects (as it has in our case using Quarkus). Specifying Let's say we create such file identical to what already is there in the jar. Now, we can build an image by running:
In this case, the buildpack is participating (because the However, now when we try to run the image we get a Class not found error for the defined entry point in the To fix this, first, we need to get rid of the requirement for a With the proposed changes, when there is a stand-alone JAR in the path, the buildpack can find and place that JAR in the image without requiring a separate |
@dmikusa I have gathered the following shell-script that show cases the use-case where the buildpack is not working as expected without the proposed changes:
|
Sorry for the delay. I got a chance to take a look at this and what you're doing with the target isn't really something that's supported presently.
You're pointing it to a whole folder of stuff and expecting the buildpack to pick through all that. The Java buildpacks expect one of two things: a.) an exploded JAR file that you've compiled in advance b.) Java source code that it can build. If you take the demo app here and give it either of those things, then it produces a functional app image. I think what you're proposing here is basically a fix for #132, and if I'm remembering this one correctly it came out of the work with Quarkus. You're hitting it in a slightly different use case, but it amounts to the same thing. You want to be able to set a path with How it's implemented really isn't that different, with the exception that your PR doesn't handle the case where other JARs (or resources) in the folder need to be on the classpath. That works in your case, cause you have only the one FAT jar, but I believe Quarkus' "fast-jar" format has the executable JAR plus some other JARs that need to be on the classpath. In that case, this PR wouldn't work. Would you be interested in submitting code changes to support that use case as well? (i.e. both #132 and #264) There is a lot of testing and verification that's required for a change like this because it impacts the build plan and there are a lot of different scenarios to cover. It would be helpful if we could do it all at once. |
@dmikusa Thanks for getting back to me. I would be happy to help with the other case, but since I don't have a good overview on all the possible cases that you mentioned, maybe we could somehow work on it together? For example, you could write down all the tests that you think are necessary, and then I could see how I can implement the required functionality, or alternatively we could also schedule a 1h pairing session. What do you think? |
@dmikusa At the moment there's basically no way to build an image using executable jar and not exploding it. The use-case should be supported, given the following in the readme:
and
executable-jar/executable/build.go Lines 83 to 87 in bba2e76
The following is not working: $ tree .
.
└── build
└── runner.jar
2 directories, 1 file
$ pack build --verbose --trust-builder --builder paketobuildpacks/builder-jammy-base -b gcr.io/paketo-buildpacks/bellsoft-liberica -b gcr.io/paketo-buildpacks/syft -b gcr.io/paketo-buildpacks/executable-jar -e 'BP_EXECUTABLE_JAR_LOCATION=build/runner.jar' my-executable-jar This scenario fails because the |
@pbusko Yes, what you're referencing is exactly why #132 is needed. Those settings only apply when building from source code because detect hasn't been updated to support multiple JARs. To be clear, I'd 100% like to see #132 implemented (I think it addresses #264 as well). This PR needs a little more though, see my previous notes. |
Do you have an example at hand? I just tried with Quarkus fatjar and the scenario described in #265 (comment) and everything works as expected. Also the #132 states:
Which is exactly what this PR does in my opinion. |
I agree that this pr looks good as it is. Imho it is rather a bugfix than a enhancement. The Also this supports the most simplest use case - only a single executable jar present. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some minor remarks - probably a matter of taste. But lgtm and fixes the bug.
executable/detect.go
Outdated
@@ -65,9 +65,15 @@ func (d Detect) Detect(context libcnb.DetectContext) (libcnb.DetectResult, error | |||
return libcnb.DetectResult{}, fmt.Errorf("unable to read manifest in %s\n%w", context.Application.Path, err) | |||
} | |||
|
|||
jarGlob, _ := cr.Resolve("BP_EXECUTABLE_JAR_LOCATION") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we move those 2 lines into the else
? Searching for a jar
is only relevant if no "Main-Class" is found yet.
So something like
if m.Get("Main-Class") {
//case 1
} else {
//search jar
if found {
//case 2
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same checks are already present in
func LoadExecutableJAR(appPath string, executableJarGlob string) (ExecutableJAR, error) { |
The detection logic can be minimised down to:
jarGlob, _ := cr.Resolve("BP_EXECUTABLE_JAR_LOCATION")
execJar, err := LoadExecutableJAR(context.Application.Path, jarGlob)
if err != nil {
return libcnb.DetectResult{}, fmt.Errorf("unable to load executable JAR\n%w", err)
}
if !reflect.DeepEqual(execJar, ExecutableJAR{}) {
d.Logger.Info("PASSED: 'Main-Class' manifest attribute found")
result.Plans[0].Provides = append(result.Plans[0].Provides, libcnb.BuildPlanProvide{Name: PlanEntryJVMApplicationPackage})
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, updated :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sap-ali the idea was to replace everything with the suggested snippet, starting from the line 64:
executable-jar/executable/detect.go
Lines 64 to 83 in 4178165
m, err := libjvm.NewManifest(context.Application.Path) | |
if err != nil { | |
return libcnb.DetectResult{}, fmt.Errorf("unable to read manifest in %s\n%w", context.Application.Path, err) | |
} | |
if _, ok := m.Get("Main-Class"); ok { | |
d.Logger.Info("PASSED: 'Main-Class' manifest attribute found") | |
result.Plans[0].Provides = append(result.Plans[0].Provides, libcnb.BuildPlanProvide{Name: PlanEntryJVMApplicationPackage}) | |
} else { | |
jarGlob, _ := cr.Resolve("BP_EXECUTABLE_JAR_LOCATION") | |
execJar, err := LoadExecutableJAR(context.Application.Path, jarGlob) | |
if err != nil { | |
return libcnb.DetectResult{}, fmt.Errorf("unable to load executable JAR\n%w", err) | |
} | |
if !reflect.DeepEqual(execJar, ExecutableJAR{}) { | |
d.Logger.Info("PASSED: 'Main-Class' manifest attribute found") | |
result.Plans[0].Provides = append(result.Plans[0].Provides, libcnb.BuildPlanProvide{Name: PlanEntryJVMApplicationPackage}) | |
} | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pbusko Got you, thanks; updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sap-ali Could you have a look at this comment - should be a minor change.
@anthonydahanne & @pivotal-david-osullivan what's your take on this? I'd be much in favor of getting this merged as is. It's fixing a bug and that should not be coupled to feature development like #132 imho. |
Hello! |
How can we continue with that? @dmikusa Could you give some details on the buildplan changes you see critical? Actually, there is no change in the buildplan at all, right, "Only" one additional case is detected. And fwiw, the case that gives the buildpack its name (it is not called "exploded executable JAR"). For me, this is a clear bugfix, since the behavior was already documented and even implemented in Imho, this is a good contribution to enable an additional use case. |
3e64d9e
to
2e46fd0
Compare
The integration tests from https://github.com/paketo-buildpacks/java passed successfully with the change from this PR. |
cc @paketo-buildpacks/java-maintainers |
@anthonydahanne WDYT, ready to merge? If not, what do you think is still missing? |
@paketo-buildpacks/java-maintainers If I recall correctly, the only concern left with this was its effect on the build plan and the lack of coverage in tests for the kind of problems that can occur in case of changes to the build plan. With paketo-buildpacks/java#1399 being merged, is there anything left to do or could we get this approved and merged? |
@paketo-buildpacks/java-maintainers Would be nice to get a comment on that. Can we merge it or what is left to do before we can? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tests pass, code is now similar to what build.go
does, which I believe is a plus.
It will detect in more cases, not less, which should not deteriorate plans involving executable-jar and other BPs
2e46fd0
to
40ed839
Compare
rebasing on top of main |
thanks for your patience all! detection of executable jar is very sensitive, hopefully everything will be smooth and it will expand use cases! |
In this PR, I'm enabling the capability to only provide a standalone executable JAR without the need to have a file in META-INF/MANIFEST.MF
[Fixes #264]