Improve plugin home defaulting.

This commit is contained in:
jregan
2019-11-03 10:04:45 -08:00
parent ba925e833d
commit d08690a6aa
11 changed files with 263 additions and 67 deletions

View File

@@ -8,6 +8,7 @@ import (
"path/filepath"
"runtime"
"sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/api/types"
)
@@ -36,9 +37,12 @@ const (
DomainName = "sigs.k8s.io"
)
func EnabledPluginConfig() *types.PluginConfig {
return MakePluginConfig(
types.PluginRestrictionsNone, DefaultAbsPluginHome())
func EnabledPluginConfig() (*types.PluginConfig, error) {
dir, err := DefaultAbsPluginHome(filesys.MakeFsOnDisk())
if err != nil {
return nil, err
}
return MakePluginConfig(types.PluginRestrictionsNone, dir), nil
}
func DisabledPluginConfig() *types.PluginConfig {
@@ -57,18 +61,61 @@ func MakePluginConfig(
// Use an obviously erroneous path, in case it's accidentally used.
const NoPluginHomeSentinal = "/no/non-builtin/plugins!"
func DefaultAbsPluginHome() string {
return filepath.Join(configRoot(), RelPluginHome)
type NotedFunc struct {
Note string
F func() string
}
// Use https://github.com/kirsle/configdir instead?
func configRoot() string {
dir := os.Getenv(XdgConfigHomeEnv)
if len(dir) == 0 {
dir = filepath.Join(
HomeDir(), XdgConfigHomeEnvDefault)
func DefaultAbsPluginHome(fSys filesys.FileSystem) (string, error) {
return FirstDirThatExistsElseError(
"plugin home directory", fSys, []NotedFunc{
{
Note: "homed in $" + KustomizePluginHomeEnv,
F: func() string {
return os.Getenv(KustomizePluginHomeEnv)
},
},
{
Note: "homed in $" + XdgConfigHomeEnv,
F: func() string {
return filepath.Join(
os.Getenv(XdgConfigHomeEnv),
ProgramName, RelPluginHome)
},
},
{
Note: "homed in default value of $" + XdgConfigHomeEnv,
F: func() string {
return filepath.Join(
HomeDir(), XdgConfigHomeEnvDefault,
ProgramName, RelPluginHome)
},
},
{
Note: "homed in home directory",
F: func() string {
return filepath.Join(
HomeDir(), ProgramName, RelPluginHome)
},
},
})
}
// FirstDirThatExistsElseError tests different path functions for
// existence, returning the first that works, else error if all fail.
func FirstDirThatExistsElseError(
what string,
fSys filesys.FileSystem,
pathFuncs []NotedFunc) (string, error) {
var nope []types.Pair
for _, dt := range pathFuncs {
dir := dt.F()
if fSys.Exists(dir) {
return dir, nil
}
nope = append(nope, types.Pair{Key: dt.Note, Value: dir})
}
return filepath.Join(dir, ProgramName)
return "", types.NewErrUnableToFind(what, nope)
}
func HomeDir() string {

View File

@@ -6,38 +6,121 @@ package pgmconfig
import (
"os"
"path/filepath"
"strings"
"testing"
"sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/api/types"
)
func TestConfigDirNoXdg(t *testing.T) {
xdg, isSet := os.LookupEnv(XdgConfigHomeEnv)
func TestDefaultAbsPluginHome_NoKustomizePluginHomeEnv(t *testing.T) {
fSys := filesys.MakeFsInMemory()
keep, isSet := os.LookupEnv(KustomizePluginHomeEnv)
if isSet {
os.Unsetenv(XdgConfigHomeEnv)
_ = os.Unsetenv(KustomizePluginHomeEnv)
}
s := configRoot()
_, err := DefaultAbsPluginHome(fSys)
if isSet {
os.Setenv(XdgConfigHomeEnv, xdg)
os.Setenv(KustomizePluginHomeEnv, keep)
}
if !strings.HasSuffix(
s,
rootedPath(XdgConfigHomeEnvDefault, ProgramName)) {
if err == nil {
t.Fatalf("expected err")
}
if !types.IsErrUnableToFind(err) {
t.Fatalf("unexpected err: %v", err)
}
}
func TestDefaultAbsPluginHome_WithKustomizePluginHomeEnv(t *testing.T) {
fSys := filesys.MakeFsInMemory()
keep, isSet := os.LookupEnv(KustomizePluginHomeEnv)
if !isSet {
keep = "whatever"
os.Setenv(KustomizePluginHomeEnv, keep)
}
fSys.Mkdir(keep)
h, err := DefaultAbsPluginHome(fSys)
if !isSet {
_ = os.Unsetenv(KustomizePluginHomeEnv)
}
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
if h != keep {
t.Fatalf("unexpected config dir: %s", h)
}
}
func TestDefaultAbsPluginHomeWithXdg(t *testing.T) {
fSys := filesys.MakeFsInMemory()
keep, isSet := os.LookupEnv(XdgConfigHomeEnv)
if !isSet {
keep = "whatever"
os.Setenv(XdgConfigHomeEnv, keep)
}
configDir := filepath.Join(keep, ProgramName, RelPluginHome)
fSys.Mkdir(configDir)
h, err := DefaultAbsPluginHome(fSys)
if !isSet {
_ = os.Unsetenv(XdgConfigHomeEnv)
}
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
if h != configDir {
t.Fatalf("unexpected config dir: %s", h)
}
}
func TestDefaultAbsPluginHomeNoConfig(t *testing.T) {
fSys := filesys.MakeFsInMemory()
keep, isSet := os.LookupEnv(XdgConfigHomeEnv)
if isSet {
_ = os.Unsetenv(XdgConfigHomeEnv)
}
_, err := DefaultAbsPluginHome(fSys)
if isSet {
os.Setenv(XdgConfigHomeEnv, keep)
}
if err == nil {
t.Fatalf("expected err")
}
if !types.IsErrUnableToFind(err) {
t.Fatalf("unexpected err: %v", err)
}
}
func TestDefaultAbsPluginHomeNoXdgWithDotConfig(t *testing.T) {
fSys := filesys.MakeFsInMemory()
configDir := filepath.Join(
HomeDir(), XdgConfigHomeEnvDefault, ProgramName, RelPluginHome)
fSys.Mkdir(configDir)
keep, isSet := os.LookupEnv(XdgConfigHomeEnv)
if isSet {
_ = os.Unsetenv(XdgConfigHomeEnv)
}
s, _ := DefaultAbsPluginHome(fSys)
if isSet {
os.Setenv(XdgConfigHomeEnv, keep)
}
if s != configDir {
t.Fatalf("unexpected config dir: %s", s)
}
}
func rootedPath(elem ...string) string {
return string(filepath.Separator) + filepath.Join(elem...)
}
func TestConfigDirWithXdg(t *testing.T) {
xdg, isSet := os.LookupEnv(XdgConfigHomeEnv)
os.Setenv(XdgConfigHomeEnv, rootedPath("blah"))
s := configRoot()
func TestDefaultAbsPluginHomeNoXdgJustHomeDir(t *testing.T) {
fSys := filesys.MakeFsInMemory()
configDir := filepath.Join(
HomeDir(), ProgramName, RelPluginHome)
fSys.Mkdir(configDir)
keep, isSet := os.LookupEnv(XdgConfigHomeEnv)
if isSet {
os.Setenv(XdgConfigHomeEnv, xdg)
_ = os.Unsetenv(XdgConfigHomeEnv)
}
if s != rootedPath("blah", ProgramName) {
s, _ := DefaultAbsPluginHome(fSys)
if isSet {
os.Setenv(XdgConfigHomeEnv, keep)
}
if s != configDir {
t.Fatalf("unexpected config dir: %s", s)
}
}

View File

@@ -12,6 +12,7 @@ import (
"strings"
"time"
"sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/api/pgmconfig"
)
@@ -29,33 +30,36 @@ type Compiler struct {
// DefaultSrcRoot guesses where the user
// has her ${g}/${v}/$lower(${k})/${k}.go files.
func DefaultSrcRoot() (string, error) {
var nope []string
var root string
root = filepath.Join(
os.Getenv("GOPATH"), "src",
pgmconfig.DomainName, pgmconfig.ProgramName, pgmconfig.RelPluginHome)
if FileExists(root) {
return root, nil
}
nope = append(nope, root)
root = pgmconfig.DefaultAbsPluginHome()
if FileExists(root) {
return root, nil
}
nope = append(nope, root)
root = filepath.Join(
pgmconfig.HomeDir(), pgmconfig.ProgramName, pgmconfig.RelPluginHome)
if FileExists(root) {
return root, nil
}
nope = append(nope, root)
return "", fmt.Errorf(
"no default src root; tried %v", nope)
func DefaultSrcRoot(fSys filesys.FileSystem) (string, error) {
return pgmconfig.FirstDirThatExistsElseError(
"source directory", fSys, []pgmconfig.NotedFunc{
{
Note: "old style $GOPATH",
F: func() string {
return filepath.Join(
os.Getenv("GOPATH"),
"src", pgmconfig.DomainName,
pgmconfig.ProgramName, pgmconfig.RelPluginHome)
},
},
{
Note: "HOME with literal 'gopath'",
F: func() string {
return filepath.Join(
pgmconfig.HomeDir(), "gopath",
"src", pgmconfig.DomainName,
pgmconfig.ProgramName, pgmconfig.RelPluginHome)
},
},
{
Note: "home directory",
F: func() string {
return filepath.Join(
pgmconfig.HomeDir(), pgmconfig.DomainName,
pgmconfig.ProgramName, pgmconfig.RelPluginHome)
},
},
})
}
// NewCompiler returns a new compiler instance.

View File

@@ -9,6 +9,7 @@ import (
"path/filepath"
"testing"
"sigs.k8s.io/kustomize/api/filesys"
. "sigs.k8s.io/kustomize/api/plugins/compiler"
)
@@ -18,7 +19,7 @@ func TestCompiler(t *testing.T) {
if err != nil {
t.Errorf("failed to make temp dir: %v", err)
}
srcRoot, err := DefaultSrcRoot()
srcRoot, err := DefaultSrcRoot(filesys.MakeFsOnDisk())
if err != nil {
t.Error(err)
}

View File

@@ -57,7 +57,12 @@ func TestLoader(t *testing.T) {
ldr := loadertest.NewFakeLoader("/foo")
pLdr := NewLoader(pgmconfig.EnabledPluginConfig(), rmF)
c, err := pgmconfig.EnabledPluginConfig()
if err != nil {
t.Fatal(err)
}
pLdr := NewLoader(c, rmF)
if pLdr == nil {
t.Fatal("expect non-nil loader")
}

View File

@@ -231,7 +231,7 @@ func definePatchDirStructure(th *kusttest_test.KustTestHarness) {
// Fails due to file load restrictor.
func TestIssue1251_Patches_ProdVsDev_Failure(t *testing.T) {
th := kusttest_test.NewKustTestHarnessAllowPlugins(t, "/app/prod")
th := kusttest_test.NewKustTestHarness(t, "/app/prod")
definePatchDirStructure(th)
th.WriteK("/app/prod", `

View File

@@ -65,7 +65,11 @@ metadata:
rf := resmap.NewFactory(resource.NewFactory(
kunstruct.NewKunstructuredFactoryImpl()), nil)
pl := pLdr.NewLoader(pgmconfig.EnabledPluginConfig(), rf)
c, err := pgmconfig.EnabledPluginConfig()
if err != nil {
t.Fatal(err)
}
pl := pLdr.NewLoader(c, rf)
tg, err := target.NewKustTarget(
ldr, valtest_test.MakeFakeValidator(), rf, transformer.NewFactoryImpl(), pl)
if err != nil {

View File

@@ -40,8 +40,11 @@ func NewKustTestHarness(t *testing.T, path string) *KustTestHarness {
}
func NewKustTestHarnessAllowPlugins(t *testing.T, path string) *KustTestHarness {
return NewKustTestHarnessFull(
t, path, fLdr.RestrictionRootOnly, pgmconfig.EnabledPluginConfig())
c, err := pgmconfig.EnabledPluginConfig()
if err != nil {
t.Fatal(err)
}
return NewKustTestHarnessFull(t, path, fLdr.RestrictionRootOnly, c)
}
func NewKustTestHarnessNoLoadRestrictor(t *testing.T, path string) *KustTestHarness {
@@ -100,7 +103,10 @@ func (th *KustTestHarness) FromMap(m map[string]interface{}) *resource.Resource
return th.rf.RF().FromMap(m)
}
func (th *KustTestHarness) FromMapAndOption(m map[string]interface{}, args *types.GeneratorArgs, option *types.GeneratorOptions) *resource.Resource {
func (th *KustTestHarness) FromMapAndOption(
m map[string]interface{},
args *types.GeneratorArgs,
option *types.GeneratorOptions) *resource.Resource {
return th.rf.RF().FromMapAndOption(m, args, option)
}

View File

@@ -11,6 +11,7 @@ import (
"strings"
"testing"
"sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/api/pgmconfig"
"sigs.k8s.io/kustomize/api/plugins/compiler"
)
@@ -75,7 +76,7 @@ func (x *PluginTestEnv) makeCompiler() *compiler.Compiler {
if err != nil {
x.t.Error(err)
}
srcRoot, err := compiler.DefaultSrcRoot()
srcRoot, err := compiler.DefaultSrcRoot(filesys.MakeFsOnDisk())
if err != nil {
x.t.Error(err)
}

View File

@@ -0,0 +1,40 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package types
import (
"fmt"
"strings"
"github.com/pkg/errors"
)
type errUnableToFind struct {
// What are we unable to find?
what string
// What things did we try?
attempts []Pair
}
func (e *errUnableToFind) Error() string {
var m []string
for _, p := range e.attempts {
m = append(m, "('"+p.Value+"'; "+p.Key+")")
}
return fmt.Sprintf(
"unable to find plugin root - tried: %s", strings.Join(m, ", "))
}
func NewErrUnableToFind(w string, a []Pair) *errUnableToFind {
return &errUnableToFind{what: w, attempts: a}
}
func IsErrUnableToFind(err error) bool {
_, ok := err.(*errUnableToFind)
if ok {
return true
}
_, ok = errors.Cause(err).(*errUnableToFind)
return ok
}

View File

@@ -5,6 +5,7 @@ package build
import (
"io"
"log"
"path/filepath"
"strings"
@@ -108,7 +109,11 @@ func (o *Options) makeOptions() *krusty.Options {
DoPrune: false,
}
if isFlagEnablePluginsSet() {
opts.PluginConfig = pgmconfig.EnabledPluginConfig()
c, err := pgmconfig.EnabledPluginConfig()
if err != nil {
log.Fatal(err)
}
opts.PluginConfig = c
} else {
opts.PluginConfig = pgmconfig.DisabledPluginConfig()
}