Bazel的数据增强

时间:2016-10-31 06:15:45

标签: datanucleus bazel

我正在尝试将Maven项目迁移到Bazel并且遇到Datanucleus增强问题。

在构建jar文件之后,Datanucleus会查看它并进行一些字节码操作以增强可持久化的类。在Bazel中执行此操作的方法是定义一个规则,该规则采用*.jar规则的java_library输出,并创建一个新的增强版本的库。

我遇到的问题是,对于我的规则,我需要来自外部库的datanucleus-core包。当我尝试从genrule $(location //third_party:datanucleus_core)访问它时,它指向一个没有类的jar:

(genrule) cmd = "echo $(location //third_party:datanucleus_core)"
bazel-out/local-fastbuild/bin/third_party/liborg_datanucleus_datanucleus_core.jar

(genrule) cmd = "jar tf $(location //third_party:datanucleus_core)"
META-INF/
META-INF/MANIFEST.MF

Bazel在jar genrule解析的$(location //third_party:datanucleus_core)文件仅包含META-INF/MANIFEST.MF,其中包含以下内容:

Manifest-Version: 1.0
Created-By: blaze

我尝试使用java_binary规则将正确的datanucleus_core.jar添加到类路径中,但Datanucleus就地增强了我的库,并且无法在磁盘上写入其更改(重写规则的输入文件)。此外,java_binary规则不应用于构建。

所以问题是在运行Datanucleus实用程序的Bazel中增强jar库的最佳方法是什么,该实用程序是作为Maven存储库中的第三方依赖项提供的?

Bazel构建标签:0.3.2-homebrew,操作系统:OS X El Capitan (10.11.6),java:1.8.0_92

更新

Datanucleus依赖声明:

# WORKSPACE
maven_jar(
    name = "org_datanucleus_datanucleus_core",
    artifact = "org.datanucleus:datanucleus-core:5.0.3",
)

# third_party/BUILD
java_library(
    name = "org_datanucleus_datanucleus_core",
    visibility = ["//visibility:public"],
    exports = ["@org_datanucleus_datanucleus_core//jar"],
)

(在我的问题中,我将org_datanucleus_datanucleus_core缩短为datanucleus_core

1 个答案:

答案 0 :(得分:3)

正如Neil Stockton所提到的,你无法在jar中增强类。所以,基本策略将是:

  1. 创建jar。
  2. 解开课程文件。
  3. 运行增强功能。
  4. 把它放回去。
  5. 步骤2& 3必须归为4,因为Bazel坚持要求您声明所有输入和输入。输出到构建规则(并且您无法知道.java文件将生成什么.class文件,因此Bazel总是将它们捣乱)。

    创建一个datanucleus.bzl文件以声明您的增强规则。它应该类似于:

    # Run datastore enhancements on the java_library named "jarname".
    def enhance(jarname):
      # src is the name of the jar file your java_library rule generates.
      src = "lib" + jarname + ".jar"
      native.genrule(
          name = jarname + "-enhancement",
          srcs = [
              src, 
              "//third_party:datanucleus_core"
          ],
          outs = [jarname + "-enhanced.jar"],
          cmd = """
    # Un-jar the .class files.
    jar tf $(location {0})
    # Run the enhance.
    classes=""
    for $$class in $$(find . -name *.class); do
      java -cp {0}:$(location //third_party:datanucleus_core) $$class
      classes="$$classes $$class"
    done
    # jar them back up.
    jar cf $@ $$classes""".format(src),
      )
    

    (我对数据存储区不太熟悉,因此cmd可能需要进行一些修改,但应该是一般的想法。)

    然后,在你的BUILD文件中,你会这样做:

    java_library(
        name = "my-lib",
        srcs = glob(["*.java"]),
        deps = ["..."],
    )
    
    # import the rule you wrote.
    load('//:datanucleus.bzl', 'enhance')
    enhance("my-lib")
    

    现在你可以做到:

    bazel build //:my-lib-enhanced.jar
    

    并使用my-lib-enhanced.jar作为其他java_规则中的依赖项。

    有关.bzl文件的更多信息:https://bazel.build/versions/master/docs/skylark/concepts.html

    编辑根据jar添加更多信息:

    有几个选项可以获得包含datanucleus内容的jar。首先,你不需要间接层:你可以说:

          srcs = [
              src, 
              "@datanucleus_core//jar"
          ],
    

    这将为您提供实际的罐子。

    如果出于某种原因,您需要将jar放在third_party中,则可以修改third_party / BUILD以创建 deploy jar ,这是一个捆绑了所有依赖关系的java二进制文件部署(因为你实际上并没有将它用作二进制文件,你可以使用你想要的主类名称):

    java_binary(
        name = "datanucleus-core",
        main_class = "whatever",
        runtime_deps = ["@org_datanucleus_datanucleus_core//jar"],
    )
    
    genrule(
        name = "your-lib",
        srcs = [":datanucleus-core_deploy.jar", ...],
    )
    

    :datanucleus-core_deploy.jar被称为隐式目标:它仅在请求时构建,但可以通过java_binary声明生成。