Implementing scoped dependencies and classpath intransitivity.

Review Request #3582 — Created March 17, 2016 and submitted — Latest diff uploaded

gmalmquist
pants
gmalmquist/provided-dependencies
3049
pants-reviews
benjyw, nhoward_tw, patricklaw, stuhood, zundel

This adds two fields to all targets: scope and _transitive.

These control how downstream tasks construct the set of targets
used for generating the classpath (in the case of JVM-related
tasks). This can be used to control similar behavior for other
(non-JVM) tasks, but this patch does not attempt to implement
all possible uses.

It is up to the individual task implementations to read and respect
these scopes. This can be facilitated by a couple utility methods,
such as BuildGraph.closure() and Target.closure(), which now take
in include_scopes, exclude_scopes, and respect_intransitive
parameters. The default values for all three of these parameters
results in the previously existing behavior of closure().

This patch modifies jvm tasks so that jvm compiles, runs, binaries,
and bundles respect scopes.

This adds a small number scopes to start with; more can easily be
added. See the Scopes class, where these are defined as constants.

  • DEFAULT - used all the time
  • COMPILE - used only at compile time
  • RUNTIME - used only at run-time (test, run, binary)
  • TEST - used only at test-time

It is possible to use these scopes and the transitive flag to
emulate the "provided" scope found in other build systems (such as
Maven, Gradle, and IntelliJ) like so:

```
jar_library(name='my-provided-target',
jars=[...],
# Only available at test-time and compile-time.
scope='compile test',
)

java_library(name='lib',
dependencies=[
intransitive(':my-provided-target'),
],
)
```

For convenience, when applying a scope to a target is done rarely
or inconsistently, it may be less verbose to use the scoped()
alias like so:

```
jar_library(name='my-library',
jars=[...],
)

java_library(name='lib',
dependencies=[
scoped(':my-library', scope='compile test'),
],
)
```

For the common pattern of "provided" dependencies (targets which
are intransitive and are scoped to 'compile test'), there is a
provided alias:

```
jar_library(name='my-target',
jars=[...],
)

java_library(name='lib',
dependencies=[
provided(':my-target'),
],
)
```

This alias simply constructs an intermediary target with the
appropriate scope and transitive arguments, and returns its address
for inclusion in a dependencies list.

Added tests to:

  • tests/python/pants_test/backend/jvm/tasks/test_scope_provided_integration.py
  • tests/python/pants_test/backend/jvm/tasks/test_scope_runtime_integration.py
  • tests/python/pants_test/build_graph/test_scopes.py

CI went green here: https://travis-ci.org/pantsbuild/pants/builds/116735387
CI went green here: https://travis-ci.org/pantsbuild/pants/builds/117721979
CI went green here: https://travis-ci.org/pantsbuild/pants/builds/117806645
CI went green here: https://travis-ci.org/pantsbuild/pants/builds/117838860
CI went green here: https://travis-ci.org/pantsbuild/pants/builds/118071196
CI went green here: https://travis-ci.org/pantsbuild/pants/builds/118090893
CI went green here: https://travis-ci.org/pantsbuild/pants/builds/118574429
CI went green here: https://travis-ci.org/pantsbuild/pants/builds/119017118

Loading...