Skip to content

Commit

Permalink
Add profile buildpack detect and build logic (#11)
Browse files Browse the repository at this point in the history
Co-authored-by: Gabe Cemaj <gcemaj@bloomberg.net>
  • Loading branch information
gcemaj and Gabe Cemaj authored Aug 5, 2022
1 parent 8204906 commit 854f33e
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 17 deletions.
1 change: 1 addition & 0 deletions buildpack.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,6 @@ include-files = [
"bin/build",
"bin/detect",
"bin/main",
"scripts/profiled-wrapper.sh",
"buildpack.toml",
]
43 changes: 41 additions & 2 deletions profile/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,52 @@
package profile

import (
"os"
"path/filepath"

"github.com/buildpacks/libcnb"
)

func Build(context libcnb.BuildContext) (libcnb.BuildResult, error) {
// NOTE: the logger is not passed into this function, that will likely be a change in libcnbv2

result := libcnb.NewBuildResult()
// TODO: implement build actions

layer, err := context.Layers.Layer(profileName)

if err != nil {
return result, err
}

execPath := layer.Exec.FilePath(ExecDScriptName)

err = os.MkdirAll(layer.Exec.Path, os.ModePerm)
if err != nil {
return result, err
}

execDScript, err := os.ReadFile(filepath.Join(context.Buildpack.Path, "scripts", "profiled-wrapper.sh"))
if err != nil {
return result, err
}

f, err := os.Create(execPath)
if err != nil {
return result, err
}
defer f.Close()

_, err = f.Write(execDScript)
if err != nil {
return result, err
}

err = os.Chmod(execPath, 0755)
if err != nil {
return result, err
}

layer.Launch = true
result.Layers = append(result.Layers, layer)

return result, nil
}
59 changes: 46 additions & 13 deletions profile/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package profile_test

import (
"os"
"path/filepath"
"testing"

. "github.com/onsi/gomega"
Expand All @@ -40,8 +41,26 @@ func (b BuildTest) SetupGomega(t *testing.T) BuildTest {

func (b BuildTest) SetupWorkspace() BuildTest {
var err error
b.context.Buildpack.Path = "../"
b.context.ApplicationPath, err = os.MkdirTemp("", "profile")
b.expect(err).NotTo(HaveOccurred())
profilePath := filepath.Join(b.context.ApplicationPath, ".profile")

f, err := os.Create(profilePath)
b.expect(err).NotTo(HaveOccurred())
defer f.Close()

b.expect(err).To(BeNil())

_, err = f.WriteString(
`
echo "Hello world"
HELLO="world"
export HELLO
`,
)
b.expect(err).NotTo(HaveOccurred())

return b
}

Expand All @@ -51,22 +70,36 @@ func (b BuildTest) RemoveWorkspace() BuildTest {
}

func (b BuildTest) Build() (libcnb.BuildContext, ExpectFunc, AfterFunc) {
return b.context, b.expect, func() { b.RemoveWorkspace() }
outputPath, _ := os.MkdirTemp("", "dotprofile_out")
os.MkdirAll(outputPath, os.ModePerm)
b.context.Layers.Path = outputPath
return b.context, b.expect, func() {
b.RemoveWorkspace()
os.RemoveAll(outputPath)
}
}

func TestBuildDoesNothingWithoutPlanEntry(t *testing.T) {
func TestBuildExecutes(t *testing.T) {
ctx, Expect, After := BuildTest{}.SetupGomega(t).SetupWorkspace().Build()
defer After()
Expect(profile.Build(ctx)).To(Equal(libcnb.BuildResult{
Layers: []libcnb.Layer{{
LayerTypes: libcnb.LayerTypes{
Build: false,
Launch: true,
},
BuildEnvironment: libcnb.Environment{},
LaunchEnvironment: libcnb.Environment{},
SharedEnvironment: libcnb.Environment{},
Name: "profile",
Path: filepath.Join(ctx.Layers.Path, "profile"),
Profile: libcnb.Profile{},
Exec: libcnb.Exec{
Path: filepath.Join(ctx.Layers.Path, "profile", "exec.d"),
},
}},
PersistentMetadata: map[string]interface{}{},
}))

Expect(profile.Build(ctx)).To(Equal(libcnb.NewBuildResult()))
}

func TestBuildExecutesWithPlanEntry(t *testing.T) {
ctx, Expect, After := BuildTest{}.SetupGomega(t).SetupWorkspace().Build()
defer After()

// TODO: test setup for a working build

// TODO: test validation for a working build
Expect(profile.Build(ctx)).To(Equal(libcnb.NewBuildResult()))
Expect(filepath.Join(ctx.Layers.Path, "profile", "exec.d", profile.ExecDScriptName)).To(BeAnExistingFile())
}
6 changes: 6 additions & 0 deletions profile/constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package profile

// Constants
const profileName = "profile"
const scriptName = ".profile"
const ExecDScriptName = "profiled-wrapper.sh"
12 changes: 11 additions & 1 deletion profile/detect.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,22 @@
package profile

import (
"os"
"os/exec"
"path/filepath"

"github.com/buildpacks/libcnb"
)

func Detect(context libcnb.DetectContext) (libcnb.DetectResult, error) {
// NOTE: the logger is not passed into this function, that will likely be a change in libcnbv2

// TODO: implement detection logic
_, shErr := exec.LookPath("bash")

profilePath := filepath.Join(context.ApplicationPath, scriptName)
if _, err := os.Stat(profilePath); shErr == nil && !os.IsNotExist(err) {
return libcnb.DetectResult{Pass: true, Plans: []libcnb.BuildPlan{}}, nil
}

return libcnb.DetectResult{Pass: false}, nil
}
3 changes: 2 additions & 1 deletion profile/detect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ func TestDetectPassesWithProfileScript(t *testing.T) {
Expect(os.WriteFile(filepath.Join(ctx.ApplicationPath, ".profile"), []byte(`echo "Hello World!"`), 0600))

Expect(profile.Detect(ctx)).To(Equal(libcnb.DetectResult{
Pass: false, // TODO: this should be true, after implemented
Pass: true,
Plans: []libcnb.BuildPlan{},
}))
}
11 changes: 11 additions & 0 deletions scripts/profiled-wrapper.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash

# Source the .profile script
source .profile
# Iterate through the list of exported env vars
for var in $(compgen -e); do
# quote the output values replacing double quotes with an escaped version
value=$(echo ${!var} | sed 's/"/\\"/g')
# output the variables to FD3
echo "${var} = \"${value}\"" 1>&3
done

0 comments on commit 854f33e

Please sign in to comment.