Skip to content

viper.Unmarshal() ignoring UnmarshalYAML interface #338

@TimJones

Description

@TimJones

I am trying to implement a custom unmarshaler for a YAML config to allow a key to support multiple types (in my personal case, a string and sequence). I am trying to configure that if the YAML value is a string type, I can manipulate it into a sequence (e.g. splitting on spaces, quotes, etc).

package main

import (
	"bytes"
	"fmt"

	"github.com/kr/pretty"
	"github.com/spf13/viper"
)

type CommandType []string

type Config struct {
	Project string
	Alias   map[string]struct {
		Command     CommandType
		Environment string
	}
}

func (cmd *CommandType) UnmarshalYAML(unmarshal func(interface{}) error) error {
	if err := unmarshal(&cmd); err != nil {
		return err
	}
	// Simply overwrite unmarshalled data PoC
	*cmd = []string{"overwritten", "values"}
	return nil
}

var data = []byte(`---
project: proof-of-concept
alias:
  poc:
    command: this can be split
    environment: poc
  other:
    command:
      - this
      - can
      - be
      - left
    environment: poc`)

func main() {
	viper.SetConfigType("yaml")
	viper.ReadConfig(bytes.NewBuffer(data))

	var cfg Config
	if err := viper.Unmarshal(&cfg); err != nil {
		panic(fmt.Errorf("Fatal error loading config: %s \n", err))
	}
	fmt.Printf("%# v\n", pretty.Formatter(cfg))
}

With the above code, I expect an output of:

main.Config{
    Project: "proof-of-concept",
    Alias:   {
        "poc": {
            Command:     {"overwritten", "values"},
            Environment: "poc",
        },
        "other": {
            Command:     {"overwritten", "values"},
            Environment: "poc",
        },
    },
}

but I get the unchanged original data instead:

main.Config{
    Project: "proof-of-concept",
    Alias:   {
        "poc": {
            Command:     {"this can be split"},
            Environment: "poc",
        },
        "other": {
            Command:     {"this", "can", "be", "left"},
            Environment: "poc",
        },
    },
}

I'm not 100% sure I have the interface right, but the API doc for gopkg.in/yaml.v2 doesn't go into detail.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions