I am trying to introduce Go vendoring (storing dependencies in a folder called vendor
) to an existing App Engine project. I have stored all dependencies in the vendor folder (using Godep as a helper) and it looks right, but running the application locally I get the following error:
go-app-builder: Failed parsing input: package "golang.org/x/net/context" is imported from multiple locations: "/Users/erik/go/src/github.com/xyz/abc/vendor/golang.org/x/net/context" and "/Users/erik/go/src/golang.org/x/net/context"
I believe the two locations should resolve to the same location, as Go applications should look in the vendor
folder first. Is there a way to make Appengine understand that both dependencies are the same?
Your project directory (where app.yaml is) is probably in the GOPATH/src. It shouldn't be. The go-app-builder will take everything in the app.yaml folder (and below) and additionally merge your GOPATH into it, meaning now you have it twice.
The solution is to move app.yaml out of the GOPATH/src folder. Additionally you'll find that
goapp test
works differently fromgoapp serve
andgoapp deploy
when it comes to resolving dependencies.So this is the solution I have been using (haven't used golang app engine in a while already) and it's the only setup I've found to work properly for all the
goapp
commands and forgovendor
to work properly (not sure aboutgodep
)details:
now run
goapp serve
andgoapp deploy
from../GOPATH/appengine/
andgoapp test ./...
from../GOPATH/src/MYPROJECT
P.S. I find the global GOPATH thing silly and simply set my GOPATH to current project folder (in the example above
/GOPATH
) and check the whole thing into version control.I managed to resolve this error using govendor instead of Godeps. The root cause appears to have been that vendored references with their own vendored references was not resolved correctly by Godeps.
The answer provided by Su-Au Hwang is also correct - you do have to keep app.yaml separate from your source.
I use a Makefile to move the
vendor
directory to a temporaryGOPATH
:I store this
Makefile
at the root of my service near thevendor
directory and simply usemake deploy
to deploy manually or from the CI.It works with Glide, Godeps or any tool that respects the Go vendor spec.
Please note, that you really need to move the
vendor
directory out of the build directory, otherwise the GoAppEngine compiler will try to build the vendor dependencies, potentially causing compile errors.I just ran into this issue myself actually. The problem occurs when you're using the App Engine tools to build any package which imports something that is using vendoring, but the package you're trying to run doesn't have the import within it's vendor directory.
So, for example, if I'm trying to run package
foo
, which imports packagebar
, and both of which use thegithub.com/gorilla/mux
library, if thebar
repository has avendor/
directory that contains gorilla/mux, but thefoo
package doesn't have gorilla mux in it'svendor/
directory, this error will occur.The reason this happens is that the
bar
package will prioritize it's ownvendor
package over the one in theGOPATH
, which is whatfoo
will be using, causing a difference in the actual location of the imported paths.The solution I found to this issue is to make sure that the
foo
directory is in theGOPATH
and has the vendor directory properly installed. It's important to note that thevendor/
convention only works from within theGOPATH
.Also got the same problem. In the docs Google suggests the following:
But this messes up my project structure, which looks like this:
Where the
myproject
directory is a git project and thevendor
folder contains all dependencies. Runninggcloud deploy
from themyproject
directory whereapp.yaml
file lives doesn't work because first,main.go
file is not in the same directory and second (from the same doc):What I ended up doing is building my own custom runtime instead, which turned out to be a very clean solution.
Simply generate the
Dockerfile
with the following command:Modify it, then specify
runtime: custom
in yourapp.yaml
and deploy normally.The trick here is of course that you're in control what gets copied where.
Here is my
Dockerfile
:Don't forget that App Engine expects your application listening on port 8080. Check out Building Custom Runtimes doc for more details.