go-gl/example

Improve unfriendly requirement that examples must be run in their package directory.

dmitshur opened this issue · 2 comments

Currently, both examples require loading some assets from disk, e.g.:

// Load the texture
texture, err := newTexture("square.png")
if err != nil {
    panic(err)
}

https://github.com/go-gl/examples/blob/45f0380c29532eac123c04e239943a4125955f8a/glfw31-gl41core-cube/cube.go#L82-L85

This means they'll work only if the working directory is the same as the Go package, otherwise there'll be a panic like:

panic: open square.png: no such file or directory

(huge stack trace)

This can be improved in many ways, and it's worth doing because this knowledge is hard to have when first looking at the examples. It's not described in any README, and even if it were, it's just unfriendly design.

Simple Enhancement

The panic(err) can be replaced with a more helpful error message, e.g.:

if err != nil {
    log.Fatalln("must be running in directory where the Go package is:", err)
}

And some notes can be added to README.

Advanced Enhancement

Assuming a proper Go installation and the source present in $GOPATH, it's possible to make the binary auto-detect where the assets folder is, and use that. For example:

func importPathToDir(importPath string) string {
    p, err := build.Import(importPath, "", build.FindOnly)
    if err != nil {
        log.Fatalln(err)
    }
    return p.Dir
}

var baseDir = importPathToDir("github.com/go-gl/examples/glfw31-gl41core-cube")

texture, err := newTexture(filepath.Join(baseDir, "square.png"))

This issue is extracted from #49 (comment).

If you're generating options then another one is https://github.com/jteeuwen/go-bindata. Unfortunately, it has a disadvantage of yet another build step if someone want's to change the image.

Imho. Info in Readme to cd into the package directory and nice error message if the image is missing would be best as the code will be simpler (easier to understand) and that's the point of the examples.

Btw. It may influence your decision, but how would I generate a distributable version of the example? Having one executable is nice but at the moment, I would need to get executable from bin directory, the image and zip them together... it seems ok for a web application but for desktop applications it would probably make sense to include assets in the binary or have some sort of installer? Just curious.

@krzychukula, that's a valid suggestion.

In #51, I've improved the error message when failing to find/load the texture assets (since it's a pretty common and realistic error). I've also made it try to change the directory to where the Go package root is on load, which would make it work as long as your GOPATH is set and the Go package is present. I think that should cover most cases and it's a simple, non-intrusive fix.

Let's start with that.

but how would I generate a distributable version of the example?

In that case, you would want to embed the assets somehow. go-bindata is an option, but personally I prefer to use vfsgen. The general idea is the same, it generates .go file that statically embeds some resources, and the app can load from there instead. For rapid development, a build tag "dev" can be used and have it load directly from disk.

But, that's extra complexity which has a cost, and it's not needed for these examples. But that's what I would suggest doing for a production binary that you want to ship.