Home > Blockchain >  How to access data files inside Go application running through Bazel go_binary
How to access data files inside Go application running through Bazel go_binary

Time:12-28

I have a BUILD.bazel file containing a go_binary target. Inside this application, I need to access a YAML file (eg. config.yml) located in the same directory.

The go_binary looks like this:

go_binary(
    name = "app1",
    data = ["config.yml"],
    embed = [":app1_lib"],
    visibility = ["//visibility:public"],
)

I can see the file is added to the /private/var/tmp/_bazel/52b44015c7f2ec78df04b9a822df93c1/execroot/__main__/bazel-out/darwin-fastbuild/bin/services/app1/app1_/app1.runfiles/__main__/services/app1 folder.

What is the best way to access this file inside my Go app?

So far I found that I could do

url := fmt.Sprintf("%s/services/app1/config.yml", os.Getenv("PWD"))

...but I would like to avoid having to specify the folder structure explicitly.

CodePudding user response:

That is simply how you access data files in Bazel... you specify the full path to the file, from the WORKSPACE root. If your file has target //services/app1:config.yml, then the path is just serivces/app1/config.yml.

It is not necessary to prefix $PWD unless you need an absolute path for some reason. The preferred way to do that would be this:

const config = "services/app1/config.yml"
abs, err := filepath.Abs(config)
if err != nil {
    return err
}

This assumes you haven't called chdir... I avoid calling chdir in my programs, mostly for this reason.

Note that it's not a URL, if you need a URL, you would:

u := url.URL{Scheme: "file", Path: filepath.ToSlash(abs)}

Also note that if you are working with files in multiple repositories, you have to include the repository, prefixed by "external". For example, @some-repo//dir/pkg:target is external/some-repo-dir/pkg/target... even if it's just ":target" in your BUILD file. Ugh, right?

Why Does Bazel Do This?

Your code may link together packages from all over your workspace. It may seem obvious that in your case, you just want to be able to read config.yml from the same directory as the package, but you could equally pass data = ["config.yml"] to some go_library() that is in your deps.

In order to make it work the same everywhere, everyone needs to use the full path to the data files. It's a bit verbose, but oh well.

If you are only invoking the go_binary from a genrule or build rule rather than bazel run, you can pass the path to the config file as a command-line argument, if you prefer. This would let you specify it without the full path.

  • Related