Skip to content

Commit

Permalink
Merge pull request #262 from paketo-buildpacks/fix-259
Browse files Browse the repository at this point in the history
Close #259: Customize gradle-wrapper.properties
  • Loading branch information
anthonydahanne authored Jul 19, 2023
2 parents ec6759d + 36f4235 commit e7587d0
Show file tree
Hide file tree
Showing 6 changed files with 241 additions and 44 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ The buildpack optionally accepts the following bindings:
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `gradle.properties` | If present, the contents of the file are copied to `$GRADLE_USER_HOME/gradle.properties` which is [picked up by gradle and merged](https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_configuration_properties) when it runs. |

### Type: `gradle-wrapper`

| Secret | Description |
|-----------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `gradle-wrapper.properties` | If present, the values of the properties file override the default ones found at <APPLICATION_ROOT>/gradle/wrapper/gradle-wrapper.properties which is [picked up by the gradle wrapper](https://docs.gradle.org/current/userguide/gradle_wrapper.html#customizing_wrapper). |


### Type: `dependency-mapping`

| Key | Value | Description |
Expand Down
32 changes: 32 additions & 0 deletions gradle/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ func (b Build) Build(context libcnb.BuildContext) (libcnb.BuildResult, error) {
if binding, ok, err := bindings.ResolveOne(context.Platform.Bindings, bindings.OfType("gradle")); err != nil {
return libcnb.BuildResult{}, fmt.Errorf("unable to resolve binding\n%w", err)
} else if ok {
b.Logger.Debug("binding of type gradle successfully detected, configuring layer")
gradlePropertiesPath, ok := binding.SecretFilePath("gradle.properties")
if ok {
gradlePropertiesFile, err := os.Open(gradlePropertiesPath)
Expand All @@ -149,6 +150,37 @@ func (b Build) Build(context libcnb.BuildContext) (libcnb.BuildResult, error) {
result.Layers = append(result.Layers, PropertiesFile{
binding,
gradleHome,
"gradle.properties",
"gradle-properties",
b.Logger,
})
}
}

gradleWrapperHome := filepath.Join("gradle", "wrapper")
if binding, ok, err := bindings.ResolveOne(context.Platform.Bindings, bindings.OfType("gradle-wrapper")); err != nil {
return libcnb.BuildResult{}, fmt.Errorf("unable to resolve binding\n%w", err)
} else if ok {
b.Logger.Debug("binding of type gradle-wrapper successfully detected, configuring layer")
gradleWrapperPropertiesPath, ok := binding.SecretFilePath("gradle-wrapper.properties")
if ok {
gradleWrapperPropertiesFile, err := os.Open(gradleWrapperPropertiesPath)
if err != nil {
return libcnb.BuildResult{}, fmt.Errorf("unable to open gradle-wrapper.properties\n%w", err)
}

hasher := sha256.New()
if _, err := io.Copy(hasher, gradleWrapperPropertiesFile); err != nil {
return libcnb.BuildResult{}, fmt.Errorf("unable to hash gradle-wrapper.properties\n%w", err)
}
md["gradle-wrapper-properties-sha256"] = hex.EncodeToString(hasher.Sum(nil))

result.Layers = append(result.Layers, PropertiesFile{
binding,
gradleWrapperHome,
"gradle-wrapper.properties",
"gradle-wrapper-properties",
b.Logger,
})
}
}
Expand Down
80 changes: 67 additions & 13 deletions gradle/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package gradle_test

import (
"errors"
"io/ioutil"
"os"
"path/filepath"
"testing"
Expand Down Expand Up @@ -48,13 +47,13 @@ func testBuild(t *testing.T, context spec.G, it spec.S) {
it.Before(func() {
var err error

ctx.Application.Path, err = ioutil.TempDir("", "build-application")
ctx.Application.Path, err = os.MkdirTemp("", "build-application")
Expect(err).NotTo(HaveOccurred())

ctx.Layers.Path, err = ioutil.TempDir("", "build-layers")
ctx.Layers.Path, err = os.MkdirTemp("", "build-layers")
Expect(err).NotTo(HaveOccurred())

homeDir, err = ioutil.TempDir("", "home-dir")
homeDir, err = os.MkdirTemp("", "home-dir")
Expect(err).NotTo(HaveOccurred())

gradlewFilepath = filepath.Join(ctx.Application.Path, "gradlew")
Expand All @@ -72,7 +71,7 @@ func testBuild(t *testing.T, context spec.G, it spec.S) {
})

it("does not contribute distribution if wrapper exists", func() {
Expect(ioutil.WriteFile(gradlewFilepath, []byte{}, 0644)).To(Succeed())
Expect(os.WriteFile(gradlewFilepath, []byte{}, 0644)).To(Succeed())
ctx.StackID = "test-stack-id"

result, err := gradleBuild.Build(ctx)
Expand All @@ -85,7 +84,7 @@ func testBuild(t *testing.T, context spec.G, it spec.S) {
})

it("makes sure that gradlew is executable", func() {
Expect(ioutil.WriteFile(gradlewFilepath, []byte{}, 0644)).To(Succeed())
Expect(os.WriteFile(gradlewFilepath, []byte{}, 0644)).To(Succeed())
ctx.StackID = "test-stack-id"

_, err := gradleBuild.Build(ctx)
Expand Down Expand Up @@ -182,7 +181,7 @@ func testBuild(t *testing.T, context spec.G, it spec.S) {
})

it("sets the settings path", func() {
Expect(ioutil.WriteFile(gradlewFilepath, []byte{}, 0644)).To(Succeed())
Expect(os.WriteFile(gradlewFilepath, []byte{}, 0644)).To(Succeed())

result, err := gradleBuild.Build(ctx)
Expect(err).NotTo(HaveOccurred())
Expand All @@ -203,7 +202,7 @@ func testBuild(t *testing.T, context spec.G, it spec.S) {
})

it("sets the settings path", func() {
Expect(ioutil.WriteFile(gradlewFilepath, []byte{}, 0644)).To(Succeed())
Expect(os.WriteFile(gradlewFilepath, []byte{}, 0644)).To(Succeed())

result, err := gradleBuild.Build(ctx)
Expect(err).NotTo(HaveOccurred())
Expand All @@ -223,7 +222,7 @@ func testBuild(t *testing.T, context spec.G, it spec.S) {
Expect(os.Unsetenv(("BP_GRADLE_BUILD_ARGUMENTS"))).To(Succeed())
})
it("sets some build arguments", func() {
Expect(ioutil.WriteFile(gradlewFilepath, []byte{}, 0644)).To(Succeed())
Expect(os.WriteFile(gradlewFilepath, []byte{}, 0644)).To(Succeed())

result, err := gradleBuild.Build(ctx)
Expect(err).NotTo(HaveOccurred())
Expand All @@ -245,7 +244,7 @@ func testBuild(t *testing.T, context spec.G, it spec.S) {
Expect(os.Unsetenv(("BP_GRADLE_ADDITIONAL_BUILD_ARGUMENTS"))).To(Succeed())
})
it("sets some build and additional build arguments", func() {
Expect(ioutil.WriteFile(gradlewFilepath, []byte{}, 0644)).To(Succeed())
Expect(os.WriteFile(gradlewFilepath, []byte{}, 0644)).To(Succeed())

result, err := gradleBuild.Build(ctx)
Expect(err).NotTo(HaveOccurred())
Expand All @@ -262,9 +261,9 @@ func testBuild(t *testing.T, context spec.G, it spec.S) {
it.Before(func() {
var err error
ctx.StackID = "test-stack-id"
ctx.Platform.Path, err = ioutil.TempDir("", "gradle-test-platform")
ctx.Platform.Path, err = os.MkdirTemp("", "gradle-test-platform")
Expect(err).NotTo(HaveOccurred())
Expect(ioutil.WriteFile(gradlewFilepath, []byte{}, 0644)).To(Succeed())
Expect(os.WriteFile(gradlewFilepath, []byte{}, 0644)).To(Succeed())
bindingPath = filepath.Join(ctx.Platform.Path, "bindings", "some-gradle")
ctx.Platform.Bindings = libcnb.Bindings{
{
Expand All @@ -277,7 +276,7 @@ func testBuild(t *testing.T, context spec.G, it spec.S) {
gradlePropertiesPath, ok := ctx.Platform.Bindings[0].SecretFilePath("gradle.properties")
Expect(os.MkdirAll(filepath.Dir(gradlePropertiesPath), 0777)).To(Succeed())
Expect(ok).To(BeTrue())
Expect(ioutil.WriteFile(
Expect(os.WriteFile(
gradlePropertiesPath,
[]byte("gradle-properties-content"),
0644,
Expand Down Expand Up @@ -309,6 +308,61 @@ func testBuild(t *testing.T, context spec.G, it spec.S) {
Expect(mdMap["gradle-properties-sha256"]).To(Equal(expected))
})
})

context("gradle wrapper properties binding exists", func() {
var bindingPath string

it.Before(func() {
var err error
ctx.StackID = "test-stack-id"
ctx.Platform.Path, err = os.MkdirTemp("", "gradle-test-platform")
Expect(err).NotTo(HaveOccurred())
Expect(os.WriteFile(gradlewFilepath, []byte{}, 0644)).To(Succeed())
bindingPath = filepath.Join(ctx.Platform.Path, "bindings", "some-gradle")
ctx.Platform.Bindings = libcnb.Bindings{
{
Name: "some-gradle",
Type: "gradle-wrapper",
Secret: map[string]string{"gradle-wrapper.properties": "gradle-wrapper-properties-content"},
Path: bindingPath,
},
}
gradlePropertiesPath, ok := ctx.Platform.Bindings[0].SecretFilePath("gradle-wrapper.properties")
Expect(os.MkdirAll(filepath.Dir(gradlePropertiesPath), 0777)).To(Succeed())
Expect(ok).To(BeTrue())
Expect(os.WriteFile(
gradlePropertiesPath,
[]byte("gradle-wrapper-properties-content"),
0644,
)).To(Succeed())
})

it.After(func() {
Expect(os.RemoveAll(ctx.Platform.Path)).To(Succeed())
})

it("contributes bound gradle-wrapper.properties", func() {
result, err := gradleBuild.Build(ctx)
Expect(err).NotTo(HaveOccurred())

Expect(result.Layers).To(HaveLen(3))
Expect(result.Layers[1].Name()).To(Equal("gradle-wrapper-properties"))
Expect(result.Layers[1])
})

it("adds the hash of gradle-wrapper.properties to the layer metadata", func() {
result, err := gradleBuild.Build(ctx)
Expect(err).NotTo(HaveOccurred())

md := result.Layers[2].(libbs.Application).LayerContributor.ExpectedMetadata
mdMap, ok := md.(map[string]interface{})
Expect(ok).To(BeTrue())
// expected: sha256 of the string "gradle-wrapper-properties-content"
expected := "8d98502ceb9504c887b12cfba9427c5338d133a2f10613cb0137695ca09c7ddc"
Expect(mdMap["gradle-wrapper-properties-sha256"]).To(Equal(expected))
})
})

}

type FakeApplicationFactory struct{}
Expand Down
50 changes: 37 additions & 13 deletions gradle/gradle_properties.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,65 @@ package gradle

import (
"fmt"
"github.com/magiconair/properties"
"github.com/paketo-buildpacks/libpak/bard"
"os"
"path/filepath"

"github.com/buildpacks/libcnb"
)

type PropertiesFile struct {
Binding libcnb.Binding
GradleHome string
Binding libcnb.Binding
GradlePropertiesHome string
GradlePropertiesFileName string
GradlePropertiesName string
Logger bard.Logger
}

func (p PropertiesFile) Contribute(layer libcnb.Layer) (libcnb.Layer, error) {
path, ok := p.Binding.SecretFilePath("gradle.properties")
path, ok := p.Binding.SecretFilePath(p.GradlePropertiesFileName)
if !ok {
return libcnb.Layer{}, nil
}

gradlePropertiesPath := filepath.Join(p.GradleHome, "gradle.properties")
if err := os.Symlink(path, gradlePropertiesPath); os.IsExist(err) {
err = os.Remove(gradlePropertiesPath)
originalPropertiesFilePath := filepath.Join(p.GradlePropertiesHome, p.GradlePropertiesFileName)
if p.GradlePropertiesName == "gradle-properties" {
p.Logger.Debug("symlinking gradle-properties bound file")
gradlePropertiesPath := originalPropertiesFilePath
if err := os.Symlink(path, gradlePropertiesPath); os.IsExist(err) {
err = os.Remove(gradlePropertiesPath)
if err != nil {
return libcnb.Layer{}, fmt.Errorf("unable to remove old symlink for %s\n%w", p.GradlePropertiesFileName, err)
}

err = os.Symlink(path, gradlePropertiesPath)
if err != nil {
return libcnb.Layer{}, fmt.Errorf("unable to create symlink for %s on retry\n%w", p.GradlePropertiesFileName, err)
}
} else if err != nil {
return libcnb.Layer{}, fmt.Errorf("unable to symlink bound %s\n%w", p.GradlePropertiesFileName, err)
}
} else if p.GradlePropertiesName == "gradle-wrapper-properties" {
file, err := os.ReadFile(path)
if err != nil {
return libcnb.Layer{}, fmt.Errorf("unable to remove old symlink for gradle.properties\n%w", err)
return libcnb.Layer{}, fmt.Errorf("unable to read bound gradle-wrapper.properties file at %s\n%w", path, err)
}

err = os.Symlink(path, gradlePropertiesPath)
p.Logger.Debugf("applying these bound gradle-wrapper-properties to default one: \n%s\n", string(file))
mergedProperties := properties.MustLoadFiles([]string{originalPropertiesFilePath, path}, properties.UTF8, true)
propertiesFile, err := os.Create(originalPropertiesFilePath)
if err != nil {
return libcnb.Layer{}, fmt.Errorf("unable to create/update original gradle-wrapper.properties file at %s\n%w", originalPropertiesFilePath, err)
}
_, err = mergedProperties.Write(propertiesFile, properties.UTF8)
if err != nil {
return libcnb.Layer{}, fmt.Errorf("unable to create symlink for gradle.properties on retry\n%w", err)
return libcnb.Layer{}, fmt.Errorf("unable to merge gradle-wrapper.properties files.\n%w", err)
}
} else if err != nil {
return libcnb.Layer{}, fmt.Errorf("unable to symlink bound gradle.properties\n%w", err)
}

return layer, nil
}

func (p PropertiesFile) Name() string {
return "gradle-properties"
return p.GradlePropertiesName
}
Loading

0 comments on commit e7587d0

Please sign in to comment.