如何在Go中处理支持包中文件的路径?

Go program with the following structure:-

├── app.go
├── bin
│   └── run.go
├── config
│   └── Config.go
└── package1
    ├── package1_file.go
    └── tmpl
        └── template.tmpl

Now, in package1_file.go, I've accessed template.tmpl via relative path like:

t, err := template.ParseFiles("./tmpl/template.tmpl")

When I run tests, tests are able to run successfully because my guess is, Go changes the current working directory when running tests for packages. go tests -v ./...

However, when I run (go build -o app && ./app) the program from the root folder, I get error complaining that file doesn't exist.

Error compiling template: open ./tmpl/template.tmpl: no such file or directory

It starts working when I change the path to package2/tmpl/template.tmpl.

The code outside package2 has nothing to do with this template file so I don't want to expose it as a parameter to a function while exposing package2. What are my options?

What is the right way to target support files like these?

You're operating under some mistaken assumptions here - primarily that the project source code or directory structure are in any way relevant at runtime. They aren't.

A Go program compiles to a single binary file that can be executed anywhere, without the source, without Go installed - just the binary. You need to consider that any time you have any kind of files in your project that you will need at runtime:

  • You need to decide how these files will be located:
    • You can mandate a path, either relative to CWD at time of execution, or absolute (but you shouldn't)
    • You can accept the path as a runtime parameter, by CLI, environment variable, config file, etc.
    • You can embed them into the binary itself using one of the many packages available (seriously - so many that a Google search for go embed static files turns up not only several libraries, but several articles comparing various libraries)
  • You need to decide how the whole thing will be packaged:
    • You could zip/tar/whatever the resources alongside the binary
    • You could zip/tar/whatever the resources and binary all together
    • As above, you could embed them into the binary as a single file

There are some choices you'll have to make as to how you want to handle this but the key takeaway is don't assume the path in your source code will be at all relevant at runtime. Parameterize at least the root path to the resources so that your code will work wherever they may be, and then your tests can pass in an appropriate path to use for testing.

You can use os.Getwd() to get the path to the root working dir. Then, concat the rest of the path to your template dir. In your case:

wd, err := os.Getwd()
if err != nil {
   log.Fatal(err)
}

t, err := template.ParseFiles(wd + "/package1/tmpl/template.tmpl")