Git Product home page Git Product logo

tools_jvm_autodeps's Introduction

Java Automatic Dependencies (Jadep)

Jadep is a Bazel BUILD file generator for Java projects. It adds BUILD dependencies that a Java file needs, aiming for <1s response times.

Jadep is intended to manage BUILD files for your own code in the current Bazel workspace (as opposed to BUILD files for third-party libraries).

Jadep is not an official Google product.

Build status

demo

Contents

Usage

~/bin/jadep path/to/File.java

Detailed Example: Migrating a Java project to Bazel

https://github.com/cgrushko/text/blob/master/migrating-gjf-to-bazel.md

Building / Installation

The following will build Jadep and its persistent server, and will copy them to ~/bin/ and ~/jadep/.

# Jadep
mkdir -p ~/bin
mkdir -p ~/jadep

bazel build -c opt //cmd/jadep

jadep=( bazel-bin/cmd/jadep/*/jadep ) # work around https://github.com/bazelbuild/rules_go/issues/1239
cp "${jadep[0]}" ~/bin/

# PackageLoader server
bazel build -c opt --nocheck_visibility //java/com/google/devtools/javatools/jade/pkgloader:GrpcLocalServer_deploy.jar

cp bazel-bin/java/com/google/devtools/javatools/jade/pkgloader/GrpcLocalServer_deploy.jar ~/jadep/
cp scripts/pkgloader_server.sh ~/jadep/

# JDK symbols [Jadep can run without these]
bazel build //:jdk_android_builtin_class_names

cp bazel-genfiles/jdk_android_builtin_class_names.txt ~/jadep/

How does it Work?

After parsing a Java file, Jadep extracts the class names it references.

It then tries to resolve each class name to BUILD rules that provide it, by employing a set of strategies ("resolvers") in sequence.

Once a set of possible BUILD rules is found, it is filtered down according to visibility, tags and so on.

The following subsections detail different parts of Jadep.

Detailed Flow

  1. Connect to the PackageLoader server (GrpcLocalServer)

  2. Jadep parses Java files to learn which fully-qualified names (FQNs) are referenced. This requires knowing which classes are defined in the same file (e.g., another inner class or a template type name) which is done by computing "jump-to-definition" information and then discarding all class names not defined in the same file.

    Implemented in https://github.com/bazelbuild/tools_jvm_autodeps/blob/master/lang/java/parser/parser.go

  3. The FQNs are passed to a sequence of "resolvers". A "resolver" returns BUILD rule candidates that can be used to satisfy a dependency on an FQN. Once a resolver returns a candidate for an FQN (i.e., it resolves it), the FQN is not passed on to additional resolvers. This is done to (a) improve performance and (b) allow ordering resolvers by accuracy to improve its quality.

    The resolver interface is defined in https://github.com/bazelbuild/tools_jvm_autodeps/blob/2d9ab49baf4b1866abe0b4d670dd356ada30fbb4/jadeplib/jadeplib.go#L51

    More details in the Resolver sections, below.

  4. Candidates are filtered by visibility, tags, etc. Visibility sometimes requires interpreting multiple BUILD files, and care was taken to interpret as many as possible in parallel.

    Code: https://github.com/bazelbuild/tools_jvm_autodeps/blob/master/filter/filter.go

  5. Finally, Jadep asks the user which rule to add.

Flow Diagram

Extracting Class Names

Jadep parses a Java file to obtain an AST, then partially resolves it: each symbol is mapped to its place of definition. For example, a call to a method maps to the method's definition.

Jadep then walks the AST and finds all

  1. symbols that must be class names based on the Java 8 grammar
  2. symbols that can be class names, and aren't defined anywhere in the same Java file

Unqualified class names are assumed to be in the same package as the Java file.

This technique gives pretty good results, but the semantics of Java make it impossible to be 100% correct. For example, a subclass has access to all the (visible) inner classes of its superclass, without having to explicitly import them. Jadep doesn't follow inheritance chains because it means reading arbitrary files, so it doesn't know which symbols are inherited.

Resolver: File System

Java source files are typically organized in the file system according to their package and class name, and this resolver utilizes this structure to find BUILD rules.

It is based on the convention that a class named com.foo.Bar will be defined in a file named <content root>/com/foo/Bar.java.

The <content root> is by default either one of {src/main/java, src/test/java}.

The resolver derives a set of file names from the set of content roots and a transformation of the class names it's looking for, and searches for BUILD rules that have these files in their srcs attributes.

The resolver also handles java_library.exports attributes and alias() rules so long as they're in the same Bazel package as the composed file name.

Resolver: JDK / Android SDK

JDK class names (e.g. java.util.List) do not need any BUILD dependencies to build, so this resolver simply maps these classes to nothing, ensuring that Jadep won't add anything for them.

Bazel Android rules don't need dependencies for Android SDK classes, so this resolver also handles these classes.

Reading BUILD files

Since Jadep interacts with existing Bazel rules (e.g., when filtering by visibility) it needs to read BUILD files.

We use Bazel's Skylark interpreter rather than Buildozer, because the latter is unable to interpret macros.

Since the Skylark interpreter is written in Java, a persistent local gRPC server is used to avoid repeatedly paying startup costs.

Extending / Hacking / Future Ideas

  • The dictresolver.go is a resolver that uses a plain-text class -> BUILD mapping encoded in CSV, and can be used as an example for how to write a performant resolver.
  • A Maven Central resolver would be useful - it would search class names in Maven Central and add their coordinates to a bazel-deps configuration.
  • Kythe could be used to generate an index that Jadep uses.

Bugs

  1. Jadep doesn't yet handle external repositories. The bazel.Label data structure is unaware of them, as is GrpcLocalServer.

Contributing

See CONTRIBUTING.md

tools_jvm_autodeps's People

Contributors

cgrushko avatar cvcal avatar lucapette avatar meistert avatar philwo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

tools_jvm_autodeps's Issues

Failed Building with Bazel 0.21

Following the steps in the README and running into issues building:

$ bazel build -c opt //cmd/jadep
Starting local Bazel server and connecting to it...
INFO: Invocation ID: 18a59634-6aa0-46bb-ab19-6a2bf04279d7
ERROR: error loading package '': Encountered error while reading extension file 'go/def.bzl': no such package '@io_bazel_rules_go//go': The native http_archive rule is deprecated. load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") for a drop-in replacement.
Use --incompatible_remove_native_http_archive=false to temporarily continue using the native rule.
ERROR: error loading package '': Encountered error while reading extension file 'go/def.bzl': no such package '@io_bazel_rules_go//go': The native http_archive rule is deprecated. load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") for a drop-in replacement.
Use --incompatible_remove_native_http_archive=false to temporarily continue using the native rule.
INFO: Elapsed time: 1.783s
INFO: 0 processes.
FAILED: Build did NOT complete successfully (0 packages loaded)
    Fetching @io_bazel_rules_go; fetching

I tried the suggestion but the build then fails with a different error:

$ bazel build -c opt //cmd/jadep --incompatible_remove_native_http_archive=false
INFO: Invocation ID: db409e9e-3580-4c14-8730-7a954bb6dab6
ERROR: /private/var/tmp/_bazel_.../external/io_bazel_rules_go/go/toolchain/BUILD.bazel:9:1: no such target '@io_bazel_rules_go//go:toolchain': target 'toolchain' not declared in package 'go'; however, a source directory of this name exists.  (Perhaps add 'exports_files(["toolchain"])' to go/BUILD, or define a filegroup?) defined by /private/var/tmp/_bazel_.../external/io_bazel_rules_go/go/BUILD.bazel and referenced by '@io_bazel_rules_go//go/toolchain:go_linux_arm64_cross_linux_mips'
ERROR: While resolving toolchains for target //cmd/jadep:jadep: invalid registered toolchain '@io_bazel_rules_go//go/toolchain:go_linux_arm64_cross_linux_mips': Analysis failed
ERROR: Analysis of target '//cmd/jadep:jadep' failed; build aborted: Analysis failed
INFO: Elapsed time: 7.154s
INFO: 0 processes.
FAILED: Build did NOT complete successfully (8 packages loaded, 37 targets configured)

Support for Scala sources

Hi,

I'm desperately seeking a tool that can perform the BUILD deps generation for Scala sources.

What is the required effort to make jvm_autodeps work with Scala?

Thanks,
Dima

[jadep] Support binding to UDS on macOS

Repro:

$ bazel-bin/java/com/google/devtools/javatools/jade/pkgloader/GrpcLocalServer --bind unix://foo
Mar 31, 2018 8:09:54 PM com.google.devtools.javatools.jade.pkgloader.GrpcLocalServer run
INFO: Binding to UDS: foo
Exception in thread "main" java.lang.UnsatisfiedLinkError: failed to load the required native library
	at io.netty.channel.epoll.Epoll.ensureAvailability(Epoll.java:81)
	at io.netty.channel.epoll.EpollEventLoop.<clinit>(EpollEventLoop.java:55)
	at io.netty.channel.epoll.EpollEventLoopGroup.newChild(EpollEventLoopGroup.java:134)
	at io.netty.channel.epoll.EpollEventLoopGroup.newChild(EpollEventLoopGroup.java:35)
	at io.netty.util.concurrent.MultithreadEventExecutorGroup.<init>(MultithreadEventExecutorGroup.java:84)
	at io.netty.util.concurrent.MultithreadEventExecutorGroup.<init>(MultithreadEventExecutorGroup.java:58)
	at io.netty.util.concurrent.MultithreadEventExecutorGroup.<init>(MultithreadEventExecutorGroup.java:47)
	at io.netty.channel.MultithreadEventLoopGroup.<init>(MultithreadEventLoopGroup.java:59)
	at io.netty.channel.epoll.EpollEventLoopGroup.<init>(EpollEventLoopGroup.java:104)
	at io.netty.channel.epoll.EpollEventLoopGroup.<init>(EpollEventLoopGroup.java:91)
	at io.netty.channel.epoll.EpollEventLoopGroup.<init>(EpollEventLoopGroup.java:68)
	at com.google.devtools.javatools.jade.pkgloader.GrpcLocalServer.newEpollEventLoopGroup(GrpcLocalServer.java:214)
	at com.google.devtools.javatools.jade.pkgloader.GrpcLocalServer.run(GrpcLocalServer.java:134)
	at com.google.devtools.javatools.jade.pkgloader.GrpcLocalServer.main(GrpcLocalServer.java:111)
Caused by: java.lang.ExceptionInInitializerError
	at io.netty.channel.epoll.Epoll.<clinit>(Epoll.java:33)
	... 13 more
Caused by: java.lang.IllegalStateException: Only supported on Linux
	at io.netty.channel.epoll.Native.loadNativeLibrary(Native.java:177)
	at io.netty.channel.epoll.Native.<clinit>(Native.java:61)
	... 14 more

Jadep's GrpcLocalServer needs to be adapted to macOS according to https://netty.io/wiki/native-transports.html#using-the-macosbsd-native-transport. Namely, use kqueue instead of epoll on macOS.

build is failing after #19

https://buildkite.com/bazel/tools-jvm-autodeps/builds/39#712e88ad-9654-4d68-bf60-4ae43b98c785

ERROR: /var/lib/buildkite-agent/builds/buildkite-worker-ubuntu1604-java8-vmhn-1/bazel/tools-jvm-autodeps/BUILD:8:1: Couldn't build file jdk_android_builtin_class_names.txt: Executing genrule //:jdk_android_builtin_class_names failed (Exit 1)
2018/07/09 07:39:57 error opening file external/local_jdk/jre/lib/rt.jar:
open external/local_jdk/jre/lib/rt.jar: no such file or directory

Seems to fail since #19
https://buildkite.com/bazel/tools-jvm-autodeps

Broken build on bazel 0.25.1

Hello. I'm trying to build jadeps on my machine.
After bazel build -c opt //cmd/jadep command, I'm getting error:

ERROR: error loading package '': Encountered error while reading extension file 'go/def.bzl': no such package '@io_bazel_rules_go//go': error loading package 'external': Could not load //external package
ERROR: error loading package '': Encountered error while reading extension file 'go/def.bzl': no such package '@io_bazel_rules_go//go': error loading package 'external': Could not load //external package
INFO: Elapsed time: 9.233s
INFO: 0 processes.
FAILED: Build did NOT complete successfully (0 packages loaded)

BR

A java_test with multiple files should provide symbols to itself

For example,
A depends on B, and both are in a java_test.
Currently, Jadep will not find a satisfying rule for B, even though the java_test provides B and there's no need for another dependency.

The same scenario works for java_library, and the reason is that java_test's are not considered because they're not rules a Java rule can deps on.

Filter by testonly

That is, a testonly=1 target should not be added as a deps to a testonly=0 target.

sort ?DEP lines

i.e., in

2018/05/21 00:45:36 Couldn't find BUILD rules for class names:                                                          
2018/05/21 00:45:36 ------------------------------------------                                                          
2018/05/21 00:45:36 ?DEP for com.google.common.collect.ImmutableList 

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.