Skip to content

Commit

Permalink
Exposes compose loader.Transform function…
Browse files Browse the repository at this point in the history
This should make it easier for people to write custom composefile
parser without duplicating too much code. It takes the default
transformers and any additional number of transformer for any
types. That way it's possible to transform a `cli/compose` map into a
custom type that would use some of `cli/compose` types and its own.

Signed-off-by: Vincent Demeester <[email protected]>
  • Loading branch information
vdemeester committed Jul 30, 2018
1 parent b4e5063 commit 4e60601
Showing 1 changed file with 20 additions and 8 deletions.
28 changes: 20 additions & 8 deletions cli/compose/loader/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,11 +265,13 @@ func getServices(configDict map[string]interface{}) map[string]interface{} {
return map[string]interface{}{}
}

func transform(source map[string]interface{}, target interface{}) error {
// Transform convert the source map into the target struct with compose types transformer
// and the specifed transformers if any.
func Transform(source map[string]interface{}, target interface{}, additionalTransformers ...Transformer) error {
data := mapstructure.Metadata{}
config := &mapstructure.DecoderConfig{
DecodeHook: mapstructure.ComposeDecodeHookFunc(
createTransformHook(),
createTransformHook(additionalTransformers...),
mapstructure.StringToTimeDurationHookFunc()),
Result: target,
Metadata: &data,
Expand All @@ -281,7 +283,13 @@ func transform(source map[string]interface{}, target interface{}) error {
return decoder.Decode(source)
}

func createTransformHook() mapstructure.DecodeHookFuncType {
// Transformer defines a map to type transformer
type Transformer struct {
TypeOf reflect.Type
Func func(interface{}) (interface{}, error)
}

func createTransformHook(additionalTransformers ...Transformer) mapstructure.DecodeHookFuncType {
transforms := map[reflect.Type]func(interface{}) (interface{}, error){
reflect.TypeOf(types.External{}): transformExternal,
reflect.TypeOf(types.HealthCheckTest{}): transformHealthCheckTest,
Expand All @@ -303,6 +311,10 @@ func createTransformHook() mapstructure.DecodeHookFuncType {
reflect.TypeOf(types.BuildConfig{}): transformBuildConfig,
}

for _, transformer := range additionalTransformers {
transforms[transformer.TypeOf] = transformer.Func
}

return func(_ reflect.Type, target reflect.Type, data interface{}) (interface{}, error) {
transform, ok := transforms[target]
if !ok {
Expand Down Expand Up @@ -380,7 +392,7 @@ func LoadServices(servicesDict map[string]interface{}, workingDir string, lookup
// the serviceDict is not validated if directly used. Use Load() to enable validation
func LoadService(name string, serviceDict map[string]interface{}, workingDir string, lookupEnv template.Mapping) (*types.ServiceConfig, error) {
serviceConfig := &types.ServiceConfig{}
if err := transform(serviceDict, serviceConfig); err != nil {
if err := Transform(serviceDict, serviceConfig); err != nil {
return nil, err
}
serviceConfig.Name = name
Expand Down Expand Up @@ -509,7 +521,7 @@ func transformUlimits(data interface{}) (interface{}, error) {
// the source Dict is not validated if directly used. Use Load() to enable validation
func LoadNetworks(source map[string]interface{}, version string) (map[string]types.NetworkConfig, error) {
networks := make(map[string]types.NetworkConfig)
err := transform(source, &networks)
err := Transform(source, &networks)
if err != nil {
return networks, err
}
Expand Down Expand Up @@ -546,7 +558,7 @@ func externalVolumeError(volume, key string) error {
// the source Dict is not validated if directly used. Use Load() to enable validation
func LoadVolumes(source map[string]interface{}, version string) (map[string]types.VolumeConfig, error) {
volumes := make(map[string]types.VolumeConfig)
if err := transform(source, &volumes); err != nil {
if err := Transform(source, &volumes); err != nil {
return volumes, err
}

Expand Down Expand Up @@ -583,7 +595,7 @@ func LoadVolumes(source map[string]interface{}, version string) (map[string]type
// the source Dict is not validated if directly used. Use Load() to enable validation
func LoadSecrets(source map[string]interface{}, details types.ConfigDetails) (map[string]types.SecretConfig, error) {
secrets := make(map[string]types.SecretConfig)
if err := transform(source, &secrets); err != nil {
if err := Transform(source, &secrets); err != nil {
return secrets, err
}
for name, secret := range secrets {
Expand All @@ -602,7 +614,7 @@ func LoadSecrets(source map[string]interface{}, details types.ConfigDetails) (ma
// the source Dict is not validated if directly used. Use Load() to enable validation
func LoadConfigObjs(source map[string]interface{}, details types.ConfigDetails) (map[string]types.ConfigObjConfig, error) {
configs := make(map[string]types.ConfigObjConfig)
if err := transform(source, &configs); err != nil {
if err := Transform(source, &configs); err != nil {
return configs, err
}
for name, config := range configs {
Expand Down

0 comments on commit 4e60601

Please sign in to comment.