gurkankaymak / hocon

go implementation of lightbend's HOCON configuration library https://github.com/lightbend/config
MIT License
79 stars 17 forks source link

Include directive incorrectly interpreting relative filepaths #28

Closed blackmichael closed 1 year ago

blackmichael commented 2 years ago

Problem

Per the HOCON docs:

For plain files on the filesystem:

  • if the included file is a relative path, then it should be located relative to the directory containing the including file. The current working directory of the process parsing a file must NOT be used when interpreting included paths.

But this does not hold true when I try to load my config files from outside of their directory. For example, if I have a project that looks like this:

myproject
├── configs
│   ├── app.conf
│   └── foo.conf
└── main.go

And app.conf has includes required("foo.conf"), main.go will fail to run hocon.ParseResource("configs/app.conf") because it can't resolve the path foo.conf from the myproject directory where main.go is running. But if I change the includes directive to be includes required("configs/foo.conf") then it works fine.

There are workarounds for this, but it breaks the standard definition of HOCON semantics and can create frustrations (for us, we want to run tests to verify config completeness from a different directory but then load configs from the same directory in shared environments where the application is running).

This bug can be exemplified in this test:

package main

import (
    "fmt"
    "github.com/gurkankaymak/hocon"
    "os"
    "testing"
)

func TestHOCON(t *testing.T) {
    testDir, _ := os.MkdirTemp("", "")
    defer os.RemoveAll(testDir)
    conf1 := `
    include required("foo.conf")
    bar {
        baz = "baz"
    }`
    conf2 := `
    foo {
        x = 7
    }`
    conf1Filepath := fmt.Sprintf("%s/app.conf", testDir)
    conf2Filepath := fmt.Sprintf("%s/foo.conf", testDir)
    _ = os.WriteFile(conf1Filepath, []byte(conf1), 0644)
    _ = os.WriteFile(conf2Filepath, []byte(conf2), 0644)

       // uncomment to fix test
       // _ = os.Chdir(testDir)

    cfg, err := hocon.ParseResource(conf1Filepath)
    if err != nil {
        t.Error(err)
    }
    fmt.Println(cfg)
}

Proposed Solution

Resolve filepaths relative to the HOCON file with the includes directive, not the current working directory of the process.

blackmichael commented 2 years ago

Oops, didn't mean to close this. I merged this into my own fork to unblock my work.