我正在尝试将Go vendoring(将依赖项存储在名为vendor
的文件夹中)引入现有的App Engine项目。我已将所有依赖项存储在vendor文件夹中(使用Godep作为帮助程序)并且看起来正确,但在本地运行应用程序时出现以下错误:
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"
我相信这两个位置应该解析到同一个位置,因为Go应用程序应首先查看vendor
文件夹。有没有办法让Appengine明白两个依赖都是一样的?
答案 0 :(得分:9)
您的项目目录(app.yaml所在的位置)可能位于GOPATH / src中。 它不应该。 go-app-builder将把app.yaml文件夹(及其下方)中的所有内容都包含在内,并将GOPATH合并到其中,这意味着现在你有两次。
解决方案是将app.yaml移出GOPATH / src文件夹。
此外,在解决依赖关系时,您会发现goapp test
与goapp serve
和goapp deploy
的工作方式不同。
所以这是我一直在使用的解决方案(暂时没有使用golang app引擎),这是我发现的唯一设置,可以正常运行所有goapp
命令和{{ 1}}正常工作(不确定govendor
)
godep
细节:
/GOPATH
├──/appengine
| ├── app.yaml
| └── aeloader.go
└──/src
└── /MYPROJECT
├── main.go
├── /handler
| └── handler.go
└── /vendor
现在来自file: GOPATH/appengine/aeloader.go (NOTE the init function is necessary, probably a bug though)
package mypackage
import (
_ "MYPROJECT"
)
func init() {
}
的{{1}}和goapp serve
以及来自goapp deploy
的{{1}}
P.S。我发现全局GOPATH的事情很愚蠢,只需将我的GOPATH设置为当前项目文件夹(在上面的示例中为../GOPATH/appengine/
)并将整个内容检查为版本控制。
答案 1 :(得分:7)
我使用Makefile将vendor
目录移动到临时GOPATH
:
TMPGOPATH := $(shell mktemp -d)
deploy:
mv vendor $(TMPGOPATH)/src
GOPATH=$(TMPGOPATH) gcloud app deploy
mv $(TMPGOPATH)/src vendor
我将此Makefile
存储在vendor
目录附近的服务根目录中,只需使用make deploy
手动部署或从CI部署。
适用于Glide,Godeps或任何尊重Go供应商规范的工具。
请注意,您确实需要将vendor
目录移出构建目录,否则GoAppEngine编译器将尝试构建供应商依赖项,从而可能导致编译错误。
答案 2 :(得分:1)
我实际上是自己遇到过这个问题。当您使用App Engine工具构建任何导入正在使用vendoring的内容的软件包时会出现问题,但您尝试运行的软件包并未在其中导入。供应商目录。
因此,例如,如果我尝试运行包foo
,导入包bar
,并且两者都使用github.com/gorilla/mux
库,如果{{} 1}} repository有一个包含gorilla / mux的bar
目录,但vendor/
包中没有gorilla mux的foo
目录,这个错误会发生。
发生这种情况的原因是,vendor/
包会优先考虑它自己的bar
包,而不是vendor
中的GOPATH
包。foo
使用,导致导入路径的实际位置不同。
我发现此问题的解决方案是确保foo
目录位于GOPATH
并正确安装了供应商目录。值得注意的是,vendor/
惯例仅适用于GOPATH
。
答案 3 :(得分:1)
我设法使用govendor而不是Godeps来解决此错误。根本原因似乎是Godeps无法正确解析带有自己的销售参考的销售参考。
Su-Au Hwang提供的答案也是正确的 - 你必须将app.yaml与你的来源分开。
答案 4 :(得分:1)
也遇到了同样的问题。 在docs Google建议如下:
为获得最佳效果,我们建议如下:
- 在应用目录中为每项服务创建一个单独的目录。
- 每个服务的目录应包含服务的app.yaml文件和一个或多个.go文件。
- 不要在服务目录中包含任何子目录。
- 您的GOPATH应指定一个位于您应用目录之外的目录,并包含您的应用导入的所有依赖项。
但这会弄乱我的项目结构,看起来像这样:
GOPATH/
└── src
└── github.com
└── username
└── myproject
├── app.yaml
├── cmd
│ └── myproject
│ └── main.go
├── handlers
│ └── api.go
├── mw
│ ├── auth.go
│ └── logger.go
└── vendor
myproject
目录是git项目,vendor
文件夹包含所有依赖项。
从gcloud deploy
文件所在的myproject
目录运行app.yaml
不起作用,因为第一个main.go
文件不在同一目录中,第二个(来自同一个文档):
您必须小心,不要将源代码放在app.yaml文件所在的应用程序目录下面或下面
我最终做的是建立自己的自定义运行时,结果证明这是一个非常干净的解决方案
只需使用以下命令生成Dockerfile
:
gcloud beta app gen-config --custom
修改它,然后在runtime: custom
中指定app.yaml
并正常部署
这里的诀窍当然是你可以控制被复制的地方
这是我的Dockerfile
:
# Dockerfile extending the generic Go image with application files for a
# single application.
FROM gcr.io/google-appengine/golang
ENV GOPATH /go
# The files which are copied are specified in the .dockerignore file
COPY . /go/src/github.com/username/myproject/
WORKDIR /go/src/github.com/username/myproject/
RUN go build -o dist/bin/myproject ./cmd/myproject
# All configuration parameters are passed through environment variables and specified in app.yaml
CMD ["/go/src/github.com/username/myproject/dist/bin/myproject"]
不要忘记App Engine希望您的应用程序在端口8080上进行侦听。有关详细信息,请查看Building Custom Runtimes doc。