grpc gradle_Gradle,Bazel和gRPC:《冰与火之歌》

grpc gradle

真是不好意思。 下面没有《权力的游戏》笑话。 诺言。

因此,您正在使用Bazel 。 可能是因为您以前有过monorepo。 或者,也许您只是认为您的Android项目中有太多模块。 或者仅仅是因为很难管理您在GitHub上整齐分离的存储库中拥有的所有那些微服务。 没关系 现在,您坚持使用Bazel。

当您切换到Bazel时,丢失的一件事就是丰富的插件生态系统,这些插件提供了Maven和Gradle之类的工具。

此外,Gradle还允许您在Kotlin中编写DSL甚至自定义任务。 所有这些善良永远消失了吗? 也许不会。

让我们看看如何使用一个Gradle插件(本例中为KrotoPlus)并使其与Bazel一起使用。

在开始之前,我们先大致介绍一下KrotoPlus插件和gRPC

所有gRPC库都将.proto文件作为输入,并以您选择的语言输出三种类:

  • 留言内容
  • 客户群
  • 服务器接口

为了便于讨论, 消息只是您的纯数据对象。 它们将具有一些字段,而这些字段将具有类型。 这就是您现在需要知道的全部。

客户端 (也称为存根)是用来调用gRPC服务的对象。 要创建客户端,通常需要指定gRPC服务器的主机和端口,然后调用一个方法,并将选择的消息传递给该方法。

服务器实现生成的服务器接口 ,然后开始侦听正确的主机和端口以能够为客户端提供服务。

您需要采取的措施如下:

gRPC Library:( proto files ) => (generated classes)

Gradle喜欢使用定义明确的项目结构,即:

your-gradle-project
  src
    main
      proto


当您运行Gradle插件并“简单地工作”时,这是因为Gradle足够聪明,可以识别您的源集并将插件应用到它们。

因此,如果您的proto目录中有一些.proto文件,我们的Gradle插件会检测到它们,然后在build目录中生成一些Java和Kotlin文件:

your-gradle-project
  build <-- your generated files will appear there
  src
    main
      proto

另一方面,Bazel对这种整洁的结构一无所知。

此外,您的proto文件将位于your-gradle-project目录之外,如下所示:

some-proto-project
   proto <-- some proto files
...
your-gradle-project
  src
    main
      proto <-- empty
...
other-proto-project
  api
    proto <-- more proto files

我们想做的是使用位于Bazel下的Gradle项目作为一个函数,该函数将获取.proto文件的路径,就好像它们是其Source Set的一部分一样,然后根据这些文件生成类。

有几种方法可以实现Gradle的行为,但这是其中一种:

import com.google.protobuf.gradle.*
...
protobuf {
    ...
    generatedFilesBaseDir = " $buildDir /generated-sources"
    ...
    dependencies {
        protobuf(files(project.properties[ "protoDir" ].toString()))
    }
    generateProtoTasks {
        ...
    }
}

重要的部分是dependencies块。 在这里,我们没有像通常那样对依赖项进行硬编码,而是从命令行获取它们:

project.properties["protoDir" ].toString()

这意味着当我们运行Gradle包装器时,我们现在将相对路径传递到.proto文件:

./gradlew generateProto -PprotoDir=../path/to/protos

我们的Gradle很好,现在就可以出发了。 接下来,让我们开始使用Bazel。

想要使用Bazel进行入侵时,您的主要工具之一就是genrule

这是表达您想在Bash shell中运行某些东西的基本方法。

但是那是什么“东西”? 它应该是gradlew ,与我们之前使用的包装相同。 但是问题是,Bazel并没有意识到这一点。

因此,让我们在gradlew所在的目录中创建一个名为BUILD的文件,并添加以下代码块:

filegroup(
    name ="gradle" ,
    srcs = [ "gradlew" ],
)

这样我们告诉Bazel:嘿,这是您应该知道的新文件。

但是,如果您尝试以这种方式运行它,Gradle会抱怨它找不到其配置。

那是因为我们只告诉Bazel将gradlew复制到它的沙箱,而不是其他任何东西。

让我们通过添加另一个保存配置的filegroup来解决此问题:

filegroup(
    name ="gradle_config" ,
    srcs = [ "build.gradle.kts" , "krotoPlusConfig.asciipb" , "settings.gradle" ]
            + glob([ "gradle/**/*" ])
            + glob([ "scripts/**/*" ]),
    visibility = [ "//visibility:public" ]
)

如您所见,我们获取了build.gradle.kts以及build.gradle.kts配置文件以及Gradle包装器本身(位于/gradle目录下)。

现在,到规则本身。 起初,它看起来令人生畏,但我们将逐行将其分解。

genrule(
    name ="run_gradle" ,
    cmd = """
    ./$(location gradlew) -p $$(dirname ./$(location gradlew)) generateProto -PprotoDir=../proto/ &&
    cp -R $$(dirname ./$(location gradlew))/build/generated-sources  $(@D)
    """ ,
    outs = [ "build/generated-sources" ],
    message = "Generating protos" ,
    srcs = [],
    tools = [ ":gradle" ] + [ ":gradle_config" ],
)
  • name是在指定库的依赖项时要引用的标签。
  • cmd是将在Shell中运行的命令。 我们待会再分解
  • outs是此命令产生的。 Bazel尝试跟踪脚本的每个输出,因此您需要在执行cmd之后告诉它您希望在文件系统中更改的内容。 如果目录build / generated-sources保持不变,Bazel将抱怨。
  • message是您等待时将显示的内容
  • srcs是您要在其上运行脚本的输入文件。 理想情况下,这些文件将是您的.proto文件。 但是在这种情况下,我们将其保留为空,因为我们使用-PprotoDir
  • tools是生成输出所需使用的文件列表。 在我们的例子中,它是Gradle Wrapper和所有配置。

现在,让我们回到cmd并了解内部发生了什么。

启动Bazel时,其根目录位于WORKSPACE文件位置,而不是gradlew所在的目录。 因此,我们使用$(location gradlew)将标签扩展到其相对位置。 在我们的示例中,它将类似于./your-gradle-project

找到Gradle Wrapper可执行文件后,我们需要告诉它在哪里可以找到其配置。 我们使用-p ,这是标准的Gradle标志。 我们知道该目录还是相对于我们的WORKSPACE ,因此是./$(location gradlew) 。 但是这次,它必须是目录,并且位置将扩展为文件的路径,因此我们使用$(dirname) 。 但是Bazel已经将$用作$(location) 。 因此,我们最终筛选了以下命令: $$(dirname)

找到配置后,我们需要告诉Gradle要运行哪个任务。 那是generateProto

现在,我们需要将Gradle指向.proto文件的位置。 但是上下文在这里从Bazel切换到Gradle,因此路径现在相对于gradlew位置: -PprotoDir=../proto/

现在Gradle和KrotoPlus努力工作来生成我们的gRPC类。 问题是,它们是在Gradle目录中生成的,而不是在Bazel沙箱中生成的。

因此,我们需要复制它们。 cp -R是一个标准的shell命令,我们已经介绍了$$dirname()含义。 您还不熟悉的唯一部分是$(@D)

那就是我们用outs指定的输出目录,因此,将生成的文件复制到我们想要的位置。

结论和下一步

如果比较麻烦,可以将Bazel和Gradle组合以生成文件。

如果您想走这条路,那么下一步应该是:

  • 记得自己清理一下。 rm -rf $$gradleDir/build会很好
  • 您可能想利用这种genrule的功能。 语法几乎保持不变,但是在函数内部时,您需要在genrule加上nativenative.genrule
  • 从长远来看,像使用-PprotoDir一样使用相对路径不是正确的选择。 尽管对于测试KrotoPlus插件很有用。 更好的选择是依靠标签。

希望,如果您已经在使用Bazel,那么本文将使您走上正确的道路。

翻译自: https://hackernoon.com/gradle-bazel-and-grpc-a-song-of-ice-and-fire-n04w330hh

grpc gradle

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值