Skip to content
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

Set $HOME to $CNB_APP_DIR when running .profile.d/ scripts at launch #23

Merged
merged 5 commits into from
Apr 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions bin/build
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

set -euo pipefail

# do not treat empty globs as literal
shopt -s nullglob

ANSI_RED="\033[1;31m"
ANSI_RESET="\033[0m"

Expand All @@ -23,6 +26,7 @@ source_dir="${bp_dir}/target"

layers_dir="${1:?}"
platform_dir="${2:?}"
app_dir="$(pwd)"

# translate new stack ID to old stack ID
export STACK="$CNB_STACK_ID"
Expand Down Expand Up @@ -118,13 +122,30 @@ cache_dir="${layers_dir}/shim"
mkdir -p "${cache_dir}"
echo "cache = true" >"${layers_dir}/shim.toml"

"${target_dir}/bin/compile" "$(pwd)" "${cache_dir}" "${platform_dir}/env"
"${target_dir}/bin/compile" "${app_dir}" "${cache_dir}" "${platform_dir}/env"

# copy profile.d scripts into a layer so they will be sourced
if [[ -d .profile.d ]]; then
profile_dir="${layers_dir}/profile"

mkdir -p "${profile_dir}/profile.d"
cp .profile.d/* "${profile_dir}/profile.d/"
for script in .profile.d/*; do
dest="${profile_dir}/profile.d/$(basename "${script}")"

# wrap each script and set $HOME to <app dir>
cat <<'EOF' >"${dest}"
__cnb_shim__original_HOME="${HOME}"
HOME=$(pwd)

EOF
cat "${script}" >>"${dest}"
cat <<'EOF' >>"${dest}"

HOME="${__cnb_shim__original_HOME}"
unset __cnb_shim__original_HOME
EOF
done

echo "launch = true" >"${profile_dir}.toml"
fi

Expand All @@ -135,4 +156,4 @@ if [[ -f "${target_dir}/export" ]]; then
fi

# run bin/release, read Procfile, and generate launch.toml
"${bp_dir}/bin/release" "${target_dir}" "${layers_dir}" "${platform_dir}" "$(pwd)"
"${bp_dir}/bin/release" "${target_dir}" "${layers_dir}" "${platform_dir}" "${app_dir}"
85 changes: 85 additions & 0 deletions build_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package cnbshim_test

import (
"bytes"
"fmt"
"io/ioutil"
"os"
"os/exec"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestBuild(t *testing.T) {
tmp, err := ioutil.TempDir("", "build")
require.NoError(t, err)
t.Cleanup(func() {
_ = os.RemoveAll(tmp)
})

// set up test env
require.NoError(t, os.MkdirAll(tmp+"/layers", 0755))
require.NoError(t, os.MkdirAll(tmp+"/platform", 0755))
require.NoError(t, os.MkdirAll(tmp+"/buildpack/target", 0755))
require.NoError(t, os.MkdirAll(tmp+"/buildpack/bin", 0755))

require.NoError(t, exec.Command("cp", "-r", "test/fixtures/build/app", tmp+"/").Run())
require.NoError(t, exec.Command("cp", "-r", "test/fixtures/build/buildpack/.", tmp+"/buildpack/target/").Run())
require.NoError(t, exec.Command("cp", "bin/build", tmp+"/buildpack/bin/").Run())
// add fake exports and release binaries
require.NoError(t, ioutil.WriteFile(tmp+"/buildpack/bin/exports", nil, 0755))
require.NoError(t, ioutil.WriteFile(tmp+"/buildpack/bin/release", nil, 0755))

// run bin/build
var out bytes.Buffer
cmd := exec.Command(tmp+"/buildpack/bin/build", tmp+"/layers", tmp+"/platform")
cmd.Dir = tmp + "/app"
cmd.Env = append(os.Environ(), "CNB_STACK_ID=heroku-20", "ALLOW_EOL_SHIMMED_BUILDER=1")
cmd.Stdout = &out
cmd.Stderr = &out
err = cmd.Run()
if _, ok := err.(*exec.ExitError); err != nil && ok {
t.Logf("bin/build output:\n%s", out.String())
}
require.NoError(t, err)

contains := []string{
"got STACK=heroku-20",
fmt.Sprintf("got arg 0=%s/app", tmp),
fmt.Sprintf("got arg 1=%s/layers/shim", tmp),
fmt.Sprintf("got arg 2=%s/platform/env", tmp),
}
for _, c := range contains {
assert.Contains(t, out.String(), c)
}

files := []string{
"/layers/profile.toml",
"/layers/profile/env.build",
"/layers/profile/profile.d/1.sh",
}
for _, f := range files {
_, err := os.Stat(tmp + f)
assert.NoError(t, err, f)
}

out = bytes.Buffer{}
cmd = exec.Command("bash", "-c", fmt.Sprintf(`
echo
echo "before HOME=$HOME"
source "%s"
echo "after HOME=$HOME"
`, tmp+"/layers/profile/profile.d/1.sh"))
cmd.Dir = tmp + "/app"
cmd.Env = []string{"HOME=/home/app"}
cmd.Stdout = &out
cmd.Stderr = &out
require.NoError(t, cmd.Run())
assert.Equal(t, fmt.Sprintf(`
before HOME=/home/app
buildpack HOME=%s
after HOME=/home/app
`, tmp+"/app"), out.String())
}
3 changes: 3 additions & 0 deletions exports_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ func TestExports(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
tmp, err := ioutil.TempDir("", "exports")
require.NoError(t, err)
t.Cleanup(func() {
_ = os.RemoveAll(tmp)
})

cmd := exec.Command("bin/exports", fmt.Sprintf("test/fixtures/%s/export", tc.name), ".", tmp)
cmd.Stdout = os.Stdout
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/build/app/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
19 changes: 19 additions & 0 deletions test/fixtures/build/buildpack/bin/compile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env bash
set -euo pipefail

i=0
for var in "$@"; do
echo "got arg ${i}=${var}"
i=$((i + 1))
done

echo "got STACK=$STACK"

mkdir .profile.d
echo 'echo "buildpack HOME=$HOME"' >.profile.d/1.sh

BIN_DIR=$(
cd "$(dirname "$0")"
pwd
) # absolute path
touch "${BIN_DIR}/../export"