我想使用Go Cloud Function中的帮助程序包。该软件包具有一些可以在多个功能之间共享的帮助程序逻辑。但是,构造这些程序包以便它们都能正常工作的正确方法是什么?该程序包应该在同一个项目中-不应作为完全独立的程序包发布和公开。
我在Google工作。这个问题的目的是主动回答常见问题,并帮助开发人员从使用Go on GCF开始。
答案 0 :(得分:5)
我们也遇到了这个问题。 @ TylerBui-Palsulich(https://stackoverflow.com/a/54255486/2307346)提供的go.mod
方法行不通,因为我们还必须从私有存储库下载依赖项。
根据Google文档:
如果函数的依赖项托管在不可公开访问的存储库中,则在部署函数之前,必须使用供应商目录来获取依赖项 (https://cloud.google.com/functions/docs/writing/specifying-dependencies-go#using_a_vendor_directory)
给出以下包结构:
cloudfunctions.go
sharedpackage
-> shared.go
go.mod
在我们的go.mod
文件中,我们定义了以下命名空间:module some/namespace
cloudfunctions.go
文件具有以下程序包定义和导入
package foobar
import (
"bitbucket.org/some/private/dependency"
"some/namespace/sharedpackage"
)
由于私有依赖性,我们无法使用go.mod文件。相反,我们提供了vendor
目录。
警告:如果您在项目的根目录下同时具有go.mod文件和供应商目录,则在云中构建函数时将忽略供应商目录的内容。为确保使用供应商目录,必须在部署之前将go.mod文件从项目的源代码中排除。如果您使用的是gcloud命令行工具,则可以使用.gcloudignore来确保go.mod没有上传。 (https://cloud.google.com/functions/docs/writing/specifying-dependencies-go#using_a_vendor_directory)
gcloud deploy
将忽略供应商目录,如果找到go.mod
,我们将使用包含以下内容的.gloudignore
文件来解决此问题:
go.mod
go.sum
最后,我们具有以下文件结构:
cloudfunctions.go
sharedpackage
-> shared.go
go.mod
vendor
.gcloudignore
在运行部署步骤时,您仍然会遇到类似以下错误:
(gcloud.functions.deploy) OperationError: code=3, message=Build failed: /tmp/sgb/gopath/src/serverlessapp/vendor/some/namespace/cloud_functions.go:5:2: cannot find package "some/namespace/sharedpackage" in any of:...
这是因为包含模块名称的go.mod
文件将被忽略。现在Go编译器不再知道some/namespace/sharedpackage
指向本地sharedpackage
目录。
我们设法通过更改模块名称以使其与程序包名称相匹配来使其工作:
将go.mod
中的模块名称更改为module foobar
将cloudfunctions.go
中的导入更改为:"foobar/sharedpackage"
:
package foobar
import (
"bitbucket.org/some/private/dependency"
"foobar/sharedpackage"
)
现在,Go编译器能够检测到foobar/sharedpackage
是foobar
包的子包。
答案 1 :(得分:4)
您可以将子包与Go modules一起使用。 Go模块是Go的新依赖关系管理解决方案-它们使您可以在GOPATH
之外工作,并可以管理每个依赖关系的确切版本。
模块还使您可以定义一组具有相同导入路径前缀的Go软件包。在编写函数时,这使您可以在模块中导入其他软件包。
您要部署的功能必须位于模块的根目录。
这是一个示例文件结构以及如何导入软件包:
.
├── cmd
│ └── main.go # Useful for testing. Can import and setup your function.
├── function.go # Can import example.com/foo/helperpackage
├── function_test.go
├── go.mod # module example.com/foo
└── helperpackage
└── helper.go
此设置在function.go
中具有您的功能,并已通过function_test.go
测试。它们位于名为example.com/foo
的模块中。 helperpackage
可以使用function.go
来导入example.com/foo/helperpackage
。
这也有一个cmd
目录,这可能对本地测试很有帮助。您可以导入example.com/foo
并启动一个HTTP服务器,该服务器将您的功能注册为HTTP处理程序。例如:
package main
import (
"log"
"net/http"
"example.com/foo"
)
func main() {
http.Handle("/HelloHTTP", foo.HelloHTTP)
log.Fatal(http.ListenAndServe(":8080", nil))
}
注意:您可以使用供应商目录来获得相同的结果。但是,函数导入的所有软件包都必须位于供应商目录中(具有完整的导入路径),该目录可以工作,但维护起来很麻烦。将子包复制到供应商目录中并不常见,因此我不建议这样做。