cmd/java/runtime/main.go (125 lines of code) (raw):
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Implements java/runtime buildpack.
// The runtime buildpack installs the JDK.
package main
import (
"encoding/json"
"fmt"
"os"
"strings"
"github.com/GoogleCloudPlatform/buildpacks/pkg/env"
gcp "github.com/GoogleCloudPlatform/buildpacks/pkg/gcpbuildpack"
"github.com/GoogleCloudPlatform/buildpacks/pkg/runtime"
)
const (
javaLayer = "java"
)
// Map with key as stackId and value as the default feature version for that stack.
// We still need to support Java11 on ubuntu18 for OSS applications.
var defaultFeatureVersion = map[string]string{
"google": "11",
"google.gae.18": "11",
"google.18": "11",
"google.gae.22": "21",
"google.min.22": "21",
"google.22": "21",
}
func main() {
gcp.Main(detectFn, buildFn)
}
func detectFn(ctx *gcp.Context) (gcp.DetectResult, error) {
if result := runtime.CheckOverride("java"); result != nil {
return result, nil
}
files := []string{
"pom.xml",
".mvn/extensions.xml",
"build.gradle",
"build.gradle.kts",
"settings.gradle.kts",
"settings.gradle",
"META-INF/MANIFEST.MF",
}
for _, f := range files {
exists, err := ctx.FileExists(f)
if err != nil {
return nil, err
}
if exists {
return gcp.OptInFileFound(f), nil
}
}
javaFiles, err := ctx.Glob("*.java")
if err != nil {
return nil, fmt.Errorf("finding .java files: %w", err)
}
if len(javaFiles) > 0 {
return gcp.OptIn("found .java files"), nil
}
jarFiles, err := ctx.Glob("*.jar")
if err != nil {
return nil, fmt.Errorf("finding .jar files: %w", err)
}
if len(jarFiles) > 0 {
return gcp.OptIn("found .jar files"), nil
}
return gcp.OptOut(fmt.Sprintf("none of the following found: %s, *.java, *.jar", strings.Join(files, ", "))), nil
}
func buildFn(ctx *gcp.Context) error {
featureVersion := stackToVersion(ctx.StackID())
if v := os.Getenv(env.RuntimeVersion); v != "" {
featureVersion = v
ctx.Logf("Using requested runtime feature version: %s", featureVersion)
} else {
ctx.Logf("Using latest Java %s runtime version. You can specify a different version with %s: https://github.com/GoogleCloudPlatform/buildpacks#configuration", featureVersion, env.RuntimeVersion)
}
l, err := ctx.Layer(javaLayer, gcp.BuildLayer, gcp.CacheLayer, gcp.LaunchLayerUnlessSkipRuntimeLaunch)
if err != nil {
return fmt.Errorf("creating %v layer: %w", javaLayer, err)
}
jdkRuntime := runtime.OpenJDK
// Java 21 should fetch Jdk from Canonical instead of Adoptium.
if strings.HasPrefix(featureVersion, "21") {
jdkRuntime = runtime.CanonicalJDK
}
_, err = runtime.InstallTarballIfNotCached(ctx, jdkRuntime, featureVersion, l)
return err
}
type binaryPkg struct {
Link string `json:"link"`
}
type binary struct {
BinaryPkg binaryPkg `json:"package"`
ImageType string `json:"image_type"`
OS string `json:"os"`
Architecture string `json:"architecture"`
}
type versionData struct {
Semver string `json:"semver"`
}
type javaRelease struct {
VersionData versionData `json:"version_data"`
Binaries []binary `json:"binaries"`
}
// stackToVersion returns the default feature version for the given stack.
func stackToVersion(stackID string) string {
featureVersion := "21"
if version, ok := defaultFeatureVersion[stackID]; ok {
featureVersion = version
}
return featureVersion
}
// parseVersionJSON parses a JSON array of version information
func parseVersionJSON(jsonStr string) (javaRelease, error) {
var releases []javaRelease
if err := json.Unmarshal([]byte(jsonStr), &releases); err != nil {
return javaRelease{}, fmt.Errorf("parsing JSON response %q: %v", jsonStr, err)
}
if len(releases) == 0 {
return javaRelease{}, fmt.Errorf("empty list of releases")
}
return releases[0], nil
}
// extractRelease returns the version name and archiveURL from a javaRelease.
func extractRelease(release javaRelease) (string, string, error) {
if len(release.Binaries) == 0 {
return "", "", fmt.Errorf("no binaries in given release %s", release.VersionData.Semver)
}
for _, binary := range release.Binaries {
if binary.ImageType == "jdk" && binary.OS == "linux" && binary.Architecture == "x64" {
return release.VersionData.Semver, binary.BinaryPkg.Link, nil
}
}
return "", "", fmt.Errorf("jdk/linux/x64 binary not found in release %s", release.VersionData.Semver)
}