在单一存储库中工作最强大的方面之一是能够在包/团队/层次结构之间共享代码。在这篇文章中,我将尝试解释一个非常简单的现实世界场景
想象一下,您想要开发一个库来显示以兆字节为单位的文件大小,您认为这可能对您的 monorepo 的其他部分有用。该库接受整数大小(例如:2048 字节),并且可以返回人性化字符串(例如:2 MB)。为了增加一些质量保证,我们还将为其编写一个测试。
从上面的场景我们知道,我们需要将此函数开发为共享库,然后由另一个包导入以供使用。 Bazel 允许我们在库中定义函数并将其导出到需要它的其他服务,从而使这变得非常简单。正如我之前在本文底部链接的文章中所解释的,我们还可以控制哪些其他库也可以导入它以供使用。
出于代码组织的目的,我们将在工作区的根目录下有一个库目录,其中有一个名为 humanize_filesize 的子目录,我们将在其中编写库代码。
让我们在 humanize_filesize.go 中编写一些非常基本的 Go 代码
package humanize_filesize import "fmt" // GetHumanizedFilesize takes size_in_bytes as an int32 pointer and returns the size in megabytes. func GetHumanizedFilesize(size_in_bytes *int32) string { if size_in_bytes != nil { size_in_megabytes := float64(*size_in_bytes) / (1024 * 1024) return fmt.Sprintf("%.4f MB", size_in_megabytes) } return "0 MB" }
此代码仅将 int32 作为输入,并返回计算出的 4 位十进制精度的可读兆字节字符串
这个功能绝对不全面,绝对可以改进,但这不是本次练习的重点。
还要断言我们的逻辑按预期工作,我们将在名为 humanize_filesize_test.go 的文件中添加一个非常基本的测试以及 go 代码
package humanize_filesize import ( "testing" ) func TestHumanizeFilesize(t *testing.T) { tests := []struct { name string size_in_bytes *int32 expected string }{ { name: "nil bytes", size_in_bytes: nil, expected: "0 MB", }, { name: "2048 bytes", size_in_bytes: int32Ptr(2048), expected: "0.0020 MB", }, { name: "0 bytes", size_in_bytes: int32Ptr(0), expected: "0.0000 MB", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := GetHumanizedFilesize(tt.size_in_bytes) if result != tt.expected { t.Errorf("expected %s, got %s", tt.expected, result) } }) } } func int32Ptr(n int32) *int32 { return &n }
一个非常简单的测试,以 nil、int32 和 0 作为输入进行基本测试
现在是如何导出此函数的有趣部分,以便可以将其导入到其他包或服务中。这是我们必须定义 BUILD.bazel 文件的地方。
load("@rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "humanize_filesize", srcs = ["humanize_filesize.go"], importpath = "basil/libraries/humanize_filesize", visibility = ["//visibility:public"], ) go_test( name = "humanize_filesize_test", srcs = ["humanize_filesize_test.go"], embed = [":humanize_filesize"], )
在这里我们定义了两个主要规则。一个用于实际库,一个用于我们编写的测试文件。
go_library 定义目标 humanize_filesize 使用 humanize_filesize.go 作为其源之一,可以通过 importpath 中指定的路径导入,并且它在工作区中公开可见,可供其他包导入。我们将在以后的帖子中学习如何控制可见性。
go_test 定义了一个测试目标,其中嵌入了 go_library 输出中的代码。
此时我们应该能够通过运行我们的测试套件来测试库,如下所示
bazel build //... && bazel run //libraries/ humanize_filesize: humanize_filesize_test
您应该能够看到如下所示的测试输出,表明所有测试均已通过。
package humanize_filesize import "fmt" // GetHumanizedFilesize takes size_in_bytes as an int32 pointer and returns the size in megabytes. func GetHumanizedFilesize(size_in_bytes *int32) string { if size_in_bytes != nil { size_in_megabytes := float64(*size_in_bytes) / (1024 * 1024) return fmt.Sprintf("%.4f MB", size_in_megabytes) } return "0 MB" }
?哇喔!!! ?现在我们知道我们的图书馆正在按预期运行。
现在让我们在 services 目录中的服务 service1 中使用这个库,我们将使用以下 go 代码和 BUILD.bazel 文件在工作区的根目录中创建该目录。
service1.go
package humanize_filesize import ( "testing" ) func TestHumanizeFilesize(t *testing.T) { tests := []struct { name string size_in_bytes *int32 expected string }{ { name: "nil bytes", size_in_bytes: nil, expected: "0 MB", }, { name: "2048 bytes", size_in_bytes: int32Ptr(2048), expected: "0.0020 MB", }, { name: "0 bytes", size_in_bytes: int32Ptr(0), expected: "0.0000 MB", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := GetHumanizedFilesize(tt.size_in_bytes) if result != tt.expected { t.Errorf("expected %s, got %s", tt.expected, result) } }) } } func int32Ptr(n int32) *int32 { return &n }
BUILD.bazel
load("@rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "humanize_filesize", srcs = ["humanize_filesize.go"], importpath = "basil/libraries/humanize_filesize", visibility = ["//visibility:public"], ) go_test( name = "humanize_filesize_test", srcs = ["humanize_filesize_test.go"], embed = [":humanize_filesize"], )
Go 代码非常简单,它导入我们之前声明的库,并使用我们库中的 GetHumanizedFilesize 函数,传递一个随机整数值并打印输出。
现在,当执行 bazel build //services/service1 时,bazel 将解析我们目标的所有依赖项,包括我们开发和构建它们的库。
service1 现在可以使用 bazel run //services/service1 执行,因为我们只定义了一个二进制目标。如果您有多个二进制目标,例如:serviceX,您可以使用 bazel run //services/service1:serviceX 来执行该目标。默认情况下,当不指定目标时,bazel 将始终尝试查找与目录同名的二进制目标并运行它。
那么...就这样吧。我们已经制作了您的第一个共享库,可供我们 monorepo 的其他部分使用。
此示例的所有代码都可以在 https://github.com/nixclix/basil/pull/3/commits/61c673b8757860bd5e60eb2ab6c35f3f4da78c87
如果您喜欢这篇文章的内容,请随时分享。另外,请订阅并留下评论,表达您对这篇文章的看法,以及您是否希望看到我改进的地方。
以上是monorepo 中共享库的实际示例的详细内容。更多信息请关注PHP中文网其他相关文章!