在Go项目中组织资产文件

I have a project that contains a folder to manage file templates, but it doesn't look like Go provides any support for non-Go-code project files. The project itself compiles to an executable, but it needs to know where this template folder is in order to operate correctly. Right now I do a search for $GOPATH/src/<templates>/templates, but this feels like kind of a hack to me because it would break if I decided to rename the package or host it somewhere else.

I've done some searching and it looks like a number of people are interested in being able to "compile" the asset files by embedding them in the final binary, but I'm not sure how I feel about this approach.

Any ideas?

Either pick a path (or a list of paths) that users are expected to put the supporting data in (/usr/local/share/myapp, ...) or just compile it into the binary.

It depends on how you are planning to distribute the program. As a package? With an installer?

Most of my programs I enjoy just having a single file to deploy and I just have a few templates to include, so I do that.

I have an example using go-bindata where I build the html template with a Makefile, but if I build with the 'devel' flag it will read the file at runtime instead to make development easier.

I can think of two options, use a cwd flag, or infer from cwd and arg 0:

-cwd path/to/assets

path/to/exe -cwd=$(path/to/exe/assets)

Internally, the exectable would chdir to wherever cwd points to, and then it can use relative paths throughout the application. This has the added benefit that the user can change the assets without having to recompile the program.

I do this for config files. Basically the order goes:

  • process cmd arguments, looking for a -cwd variable (it defaults to empty)
  • chdir to -cwd
  • parse config file
  • reparse cmd arguments, overwriting the settings in the config file

I'm not sure how many arguments your app has, but I've found this to be very useful, especially since Go doesn't have a standard packaging tool that will compile these assets in.

infer from arg 0

Another option is to use the first argument and get the path to the executable. Something like this:

here := path.Dir(os.Args[0])
if !path.IsAbs(os.Args[0]) {
    here = path.Join(os.Getwd(), here)
}

This will get you the path to where the executable is. If you're guaranteed the user won't move this without moving the rest of your assets, you can use this, but I find it much more flexible to use the above -cwd idea, because then the user can place the executable anywhere on their system and just point it to the assets.

The best option would probably be a mixture of the two. If the user doesn't supply a -cwd flag, they probably haven't moved anything, so infer from arg 0 and the cwd. The cwd flag overrides this.