-
Notifications
You must be signed in to change notification settings - Fork 42
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: improved resource referencing and throw errors for invalid expr…
…essions (#54)
- Loading branch information
Showing
11 changed files
with
356 additions
and
163 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package compose | ||
|
||
import ( | ||
"maps" | ||
"os" | ||
"strings" | ||
) | ||
|
||
// EnvVarTracker is used to provide the `environment` resource type. This tracks what keys are accessed and replaces | ||
// them with outputs that are environment variable references that docker compose will support. | ||
// This keeps track of which keys were accessed so that we can produce a reference file or list of keys for the user | ||
// to understand what inputs docker compose will require at launch time. | ||
type EnvVarTracker struct { | ||
// lookup is an environment variable lookup function, if nil this will be defaulted to os.LookupEnv | ||
lookup func(key string) (string, bool) | ||
// accessed is the map of accessed environment variables and the value they had at access time | ||
accessed map[string]string | ||
} | ||
|
||
func (e *EnvVarTracker) Accessed() map[string]string { | ||
return maps.Clone(e.accessed) | ||
} | ||
|
||
// the env var tracker is a resource itself (an environment resource) | ||
var _ ResourceWithOutputs = (*EnvVarTracker)(nil) | ||
|
||
func (e *EnvVarTracker) LookupOutput(keys ...string) (interface{}, error) { | ||
if len(keys) == 0 { | ||
panic("requires at least 1 key") | ||
} | ||
envVarKey := strings.ToUpper(strings.Join(keys, "_")) | ||
|
||
// in theory we can replace more unexpected characters | ||
envVarKey = strings.ReplaceAll(envVarKey, "-", "_") | ||
envVarKey = strings.ReplaceAll(envVarKey, ".", "_") | ||
|
||
if e.lookup == nil { | ||
e.lookup = os.LookupEnv | ||
} | ||
if e.accessed == nil { | ||
e.accessed = make(map[string]string, 1) | ||
} | ||
|
||
if v, ok := e.lookup(envVarKey); ok { | ||
e.accessed[envVarKey] = v | ||
} else { | ||
e.accessed[envVarKey] = "" | ||
} | ||
return "${" + envVarKey + "}", nil | ||
} | ||
|
||
func (e *EnvVarTracker) GenerateResource(resName string) ResourceWithOutputs { | ||
return &envVarResourceTracker{ | ||
inner: e, | ||
prefix: resName, | ||
} | ||
} | ||
|
||
// envVarResourceTracker is a child object of EnvVarTracker and is used as a fallback behavior for resource types | ||
// that are not supported natively: we treat them like environment variables instead with a prefix of the resource name. | ||
type envVarResourceTracker struct { | ||
prefix string | ||
inner *EnvVarTracker | ||
} | ||
|
||
func (e *envVarResourceTracker) LookupOutput(keys ...string) (interface{}, error) { | ||
next := make([]string, 1+len(keys)) | ||
next[0] = e.prefix | ||
for i, k := range keys { | ||
next[1+i] = k | ||
} | ||
return e.inner.LookupOutput(next...) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package compose | ||
|
||
import "fmt" | ||
|
||
// ResourceWithOutputs is an interface that resource implementations in the future may provide. | ||
// The keys here are the parts of a .-separated path traversal down a tree to return some data from the outputs of | ||
// the provisioned resource. If an error occurs looking up the output, an error should be thrown. | ||
// nil is a valid result since some resources may return null in their outputs. | ||
type ResourceWithOutputs interface { | ||
LookupOutput(keys ...string) (interface{}, error) | ||
} | ||
|
||
type resourceWithStaticOutputs map[string]interface{} | ||
|
||
func (r resourceWithStaticOutputs) LookupOutput(keys ...string) (interface{}, error) { | ||
var resolvedValue interface{} | ||
resolvedValue = (map[string]interface{})(r) | ||
for _, k := range keys { | ||
mapV, ok := resolvedValue.(map[string]interface{}) | ||
if !ok { | ||
return "", fmt.Errorf("cannot lookup key '%s', context is not a map", k) | ||
} | ||
resolvedValue, ok = mapV[k] | ||
if !ok { | ||
return "", fmt.Errorf("key '%s' not found", k) | ||
} | ||
} | ||
return resolvedValue, nil | ||
} | ||
|
||
var _ ResourceWithOutputs = (resourceWithStaticOutputs)(nil) |
Oops, something went wrong.