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

Resolve PORTER_HOME when it's symlinked #139

Merged
merged 2 commits into from
Feb 8, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
40 changes: 31 additions & 9 deletions pkg/config/config.go
Expand Up @@ -23,9 +23,16 @@ const (
EnvACTION = "CNAB_ACTION"
)

// These are functions that afero doesn't support, so this lets us stub them out for tests to set the
// location of the current executable porter binary and resolve PORTER_HOME.
var getExecutable = os.Executable
var evalSymlinks = filepath.EvalSymlinks

type Config struct {
*context.Context
Manifest *Manifest

porterHome string
}

// New Config initializes a default porter configuration.
Expand All @@ -37,19 +44,34 @@ func New() *Config {

// GetHomeDir determines the path to the porter home directory.
func (c *Config) GetHomeDir() (string, error) {
home, ok := os.LookupEnv(EnvHOME)
if ok {
return home, nil
if c.porterHome != "" {
return c.porterHome, nil
}

porterPath, err := os.Executable()
if err != nil {
return "", errors.Wrap(err, "could not get path to the executing porter binary")
}
home := os.Getenv(EnvHOME)

porterDir := filepath.Dir(porterPath)
if home == "" {
porterPath, err := getExecutable()
if err != nil {
return "", errors.Wrap(err, "could not get path to the executing porter binary")
}

// This is for the scenario when someone symlinks the ~/.porter/porter binary to /usr/local/porter
// We try to resolve back to the original location so that we can find the mixins, etc next to it.
hardPath, err := evalSymlinks(porterPath)
if err != nil { // if we have trouble resolving symlinks, skip trying to help people who used symlinks
fmt.Fprintln(c.Err, errors.Wrapf(err, "WARNING could not resolve %s for symbolic links\n", porterPath))
} else if hardPath != porterPath {
if c.Debug {
fmt.Fprintf(c.Err, "Resolved porter binary from %s to %s\n", porterPath, hardPath)
}
porterPath = hardPath
}
home = filepath.Dir(porterPath)
}

return porterDir, nil
c.porterHome = home
return c.porterHome, nil
}

// GetTemplatesDir determines the path to the templates directory.
Expand Down
22 changes: 12 additions & 10 deletions pkg/config/config_test.go
Expand Up @@ -3,7 +3,6 @@ package config
import (
"io/ioutil"
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/assert"
Expand All @@ -12,24 +11,27 @@ import (

func TestConfig_GetHomeDir(t *testing.T) {
c := NewTestConfig(t)

// Set up a test porter home
testEntrypoint, err := os.Executable()
testHome := filepath.Dir(testEntrypoint)
require.NoError(t, err)
err = c.FileSystem.MkdirAll(testHome, os.ModePerm)
require.NoError(t, err)
c.SetupPorterHome()

home, err := c.GetHomeDir()
require.NoError(t, err)

assert.Equal(t, testHome, home)
assert.Equal(t, "/root/.porter", home)
}

func TestConfig_GetHomeDir_HomeSet(t *testing.T) {
func TestConfig_GetHomeDirFromSymlink(t *testing.T) {
c := NewTestConfig(t)
c.SetupPorterHome()

// Set up no PORTER_HOME, and /usr/local/bin/porter -> ~/.porter/porter
os.Unsetenv(EnvHOME)
getExecutable = func() (string, error) {
return "/usr/local/bin/porter", nil
}
evalSymlinks = func(path string) (string, error) {
return "/root/.porter/porter", nil
}

home, err := c.GetHomeDir()
require.NoError(t, err)

Expand Down