pubref / rules_maven

Transitive maven dependencies with Bazel.
Other
33 stars 7 forks source link

Usage example #11

Closed promiseofcake closed 7 years ago

promiseofcake commented 7 years ago

Forgive me is this is apparent, but how does one generate the WORKSPACE output as described in 2a?

Here is a sample repo (using example from the README.md): https://github.com/promiseofcake/rules_maven_example

How do I convert the guice dependency:

maven_repository(
  name = "guice",
  deps = [
    'com.google.inject:guice:4.1.0',
  ],
)

into:

maven_repository(
  name = 'guice',
  deps = [
    'com.google.inject:guice:4.1.0',
  ],
  transitive_deps = [
    '0235ba8b489512805ac13a8f9ea77a1ca5ebe3e8:aopalliance:aopalliance:1.0',
    '6ce200f6b23222af3d8abb6b6459e6c44f4bb0e9:com.google.guava:guava:19.0',
    'eeb69005da379a10071aa4948c48d89250febb07:com.google.inject:guice:4.1.0',
    '6975da39a7040257bd51d21a231b76c915872d38:javax.inject:javax.inject:1',
  ],
)

It seems to differ from the rules_protobuf paradigms in that I am not specifying a specific skylark macro such as java_proto_library in my BUILD file which can then be triggered.

pcj commented 7 years ago

Hey @promiseofcake thanks for asking. So, when you initially write the rule, you don't manually type in the transitive_deps yourself, you just type in the roots for the transitive search (in this example just com.google.inject:guice:4.1.0.

What will happen is that a new external workspace will be generated as @guice (the name of the maven_repository rule) with a new file called rules.bzl. That file contains generated maven_jar definitions for all the transitive dependencies. It also contains a guice_${configuration} rule that loads the transitive maven jars foreach gradle "configuration". The most common configuration is "compile", but there are a bunch of other ones.

In the next line of your WORKSPACE, tell bazel to load that file for the configuration you want, and then invoke it.

load("@guice//:rules.bzl", "guice_compile")
guice_compile()

The second file that is generated is @guice//:BUILD. This contains generated java_library, java_import rules (which aggregate the transitive set of jars) that you actually depend on in your own java_library or java_binary rules. So, to actually use that set, depend on it:

java_binary(
   name = "foo",
   srcs = [...],
   deps = ["@guice//:compile"] # name of configuration matches the one you loaded
)

Since bazel is super lazy, nothing happens until you do something that actually requires the upstream deps to get evaluated. So when you bazel build src/main/java:foo, bazel will go back and actually generate the @guice workspace etc.

When that occurs, rules_maven compares the maven_repository rule you wrote to the one where all the transitive deps are included. If there is a discrepancy, it will print out the "closed-form" rule with all the transitive_deps listed for you.

You then have to manually copy-paste the text from your terminal back into your WORKSPACE file. Assuming there is congruence of expected / actual values of the transitive_deps, the rule will be silent and no output will be printed to the console. (this is the paragraph that actually answers your question).

Hope that made sense! Maybe I should put together a short video on how to do it.

pcj commented 7 years ago

FYI this two-stage loading pattern is similar to how it works in bazelbuild/rules_python.

They may have explained it better, so if you understand one you understand both. cc @mattmoor

mattmoor commented 7 years ago

@davidstanke FYI

promiseofcake commented 7 years ago

Thank you for the thorough explanation, I was able to get that working!

pcj commented 7 years ago

Good to hear it. FYI it's always useful to inspect the generated files:

$ less $(bazel info output_base)/external/guice/rules.bzl
$ less $(bazel info output_base)/external/guice/BUILD
$ less $(bazel info output_base)/external/guice/build.gradle

And a way to see all the available external workspaces:

$ bazel query //external:*