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

Parsing YAML files with anchors does not keep pointers to anchors when unmarshalling #71

Closed
timgws opened this issue Jan 9, 2020 · 4 comments · Fixed by #72
Closed

Comments

@timgws
Copy link

timgws commented Jan 9, 2020

Thanks @goccy for your work on this package :)

Similar to #69, I have a configuration file that looks like this:

hosts:
  - host: &host1
      hostname: queue.example.com
      username: queue1
      password: queue1
      port: 5672

  - host: &host2
      hostname: queue2.example.com
      username: queue2
      password: queue2
      port: 5672

queues:
  - name: queue
    host: *host1
  - name: queue2
    host: *host1
  - name: queue3
    host: *host2

I have a set of structs in a separate package, describing the YAML file

package configuration

type HostList struct {
	Host *Host  `yaml:",inline,anchor"`
	Name string `yaml:","`
}

type Host struct {
	*Host    `yaml:",omitempty"`
	Hostname string
	Username string
	Password string
}

type Queue struct {
	Name  string `yaml:","`
	*Host `yaml:",alias"`
}

type ConfigFile struct {
	HostList []*HostList `yaml:"hosts"`
	Queues   []*Queue    `yaml:"queues"`
}

I am reading my configuration file like this

func Read(configFile string) (error, ConfigFile) {
	var cf ConfigFile
	yamlFile, err := ioutil.ReadFile(configFile)
	if err != nil {
		return err, cf
	}

	err = yaml.Unmarshal(yamlFile, &cf)
	if err != nil {
		// clear the config file that might have been partially parsed
		var cf ConfigFile
		return err, cf
	}

	return nil, cf
}

and inside my main.go, I have the following code:

	err, cf = configuration.Read(configFile)
	if err != nil {
		log.Fatal(err)
		return err
	}

	fmt.Println(Configuration.Queues[0].Host.Hostname)
	fmt.Println(Configuration.Queues[1].Host.Hostname)

	Configuration.Queues[0].Host.Hostname = "updated_hostname.example.org"
	
	fmt.Println(Configuration.Queues[0].Host.Hostname)
	fmt.Println(Configuration.Queues[1].Host.Hostname)

Expected output:

queue.example.com
queue.example.com
updated_hostname.example.org
updated_hostname.example.org

Actual output:

queue.example.com
queue.example.com
updated_hostname.example.org
queue.example.com

It seems that the anchor in the created document to host1 is not being respected when unmarshalling the document.

I would expect that both Configuration.Queues[0].Host and Configuration.Queues[1].Host would be a pointer to Configuration.Hosts[0].Host, reflecting the document's intent.

@goccy
Copy link
Owner

goccy commented Jan 9, 2020

@timgws

I fixed with #72 and released as v1.2.0 !
If you like this library, I'd be happy if you could promote this around .

Thanks

@timgws
Copy link
Author

timgws commented Jan 10, 2020

I fixed with #72 and released as v1.2.0 !

I just tested this with the above code, and it does not work. Configuration.HostList[0] and Configuration.HostList[1] are both empty.

The Actual output remains the same as the previous commit.

@goccy
Copy link
Owner

goccy commented Jan 10, 2020

@timgws

The above code is wrong, it does not work .
( HostList and Host definition is wrong )

The following code works fine .

package main

import (
	"github.com/goccy/go-yaml"
)

type Host struct {
	Hostname string
	Username string
	Password string
}

type HostList struct {
	Host *Host `yaml:",anchor"`
}

type Queue struct {
	Name  string `yaml:","`
	*Host `yaml:",alias"`
}

type ConfigFile struct {
	HostList []*HostList `yaml:"hosts"`
	Queues   []*Queue    `yaml:"queues"`
}

func main() {
	yml := `
hosts:
  - host: &host1
      hostname: queue.example.com
      username: queue1
      password: queue1
      port: 5672

  - host: &host2
      hostname: queue2.example.com
      username: queue2
      password: queue2
      port: 5672

queues:
  - name: queue
    host: *host1
  - name: queue2
    host: *host1
  - name: queue3
    host: *host2
`

	var cf ConfigFile
	if err := yaml.Unmarshal([]byte(yml), &cf); err != nil {
		panic(err)
	}
	cf.Queues[0].Host.Hostname = "updated"
}

@timgws
Copy link
Author

timgws commented Jan 10, 2020

Ah! It happened when HostList had inline inside the Host yaml parameters.

Thanks so much for all your help here @goccy

I will try over the next couple of days to get goccy/go-yaml to marshel files in the same format that was unmarshaled.

Words can't explain how much I appreciate the last two commits :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants