-
-
Notifications
You must be signed in to change notification settings - Fork 646
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Zinc 1.0.0 upgrade: Python portion (#4729)
### Problem (this change depends on #4728) As described on #4728, we currently need internal knowledge of zinc analysis in order to make it portable, and to extract products that are used by other tasks. Since the zinc analysis format is changing significantly (moving to protobuf, gaining/losing fields, etc), we need to stop parsing it. ### Solution Incorporates the version of the zinc wrapper published in #4728, and uses it in a `analysis.zinc` task to generate the `product_deps_by_src` and `classes_by_source` products from a `zinc_analysis` product published by zinc. Expands the extracted `Zinc` subsystem from #4720 to encapsulate compile dependency calculation, and expose the `FingerprintStrategy` and `DependencyContext` that `compile.zinc` was using. ### Result Zinc analysis is now a black box from the perspective of the pants python code. Also, the `compile.jvm-dep-check` task moved to the `lint` goal, and gained the unused dependency checks that used to be inlined in `compile.zinc` (and which would have prevented separation of the analysis extraction task). Fixes #4477, fixes #4513, fixes #4185, fixes #5444, and hopefully fixes a few other odd incremental compilation bugs.
- Loading branch information
Showing
69 changed files
with
918 additions
and
2,372 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
118 changes: 118 additions & 0 deletions
118
src/python/pants/backend/jvm/subsystems/dependency_context.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
# coding=utf-8 | ||
# Copyright 2018 Pants project contributors (see CONTRIBUTORS.md). | ||
# Licensed under the Apache License, Version 2.0 (see LICENSE). | ||
|
||
from __future__ import (absolute_import, division, generators, nested_scopes, print_function, | ||
unicode_literals, with_statement) | ||
|
||
import hashlib | ||
|
||
from pants.backend.codegen.protobuf.java.java_protobuf_library import JavaProtobufLibrary | ||
from pants.backend.codegen.thrift.java.java_thrift_library import JavaThriftLibrary | ||
from pants.backend.jvm.subsystems.java import Java | ||
from pants.backend.jvm.subsystems.scala_platform import ScalaPlatform | ||
from pants.backend.jvm.targets.annotation_processor import AnnotationProcessor | ||
from pants.backend.jvm.targets.jar_library import JarLibrary | ||
from pants.backend.jvm.targets.javac_plugin import JavacPlugin | ||
from pants.backend.jvm.targets.scalac_plugin import ScalacPlugin | ||
from pants.base.fingerprint_strategy import FingerprintStrategy | ||
from pants.build_graph.aliased_target import AliasTarget | ||
from pants.build_graph.resources import Resources | ||
from pants.build_graph.target import Target | ||
from pants.build_graph.target_scopes import Scopes | ||
from pants.subsystem.subsystem import Subsystem | ||
|
||
|
||
class SyntheticTargetNotFound(Exception): | ||
"""Exports were resolved for a thrift target which hasn't had a synthetic target generated yet.""" | ||
|
||
|
||
class DependencyContext(Subsystem): | ||
"""Implements calculating `exports` and exception (compiler-plugin) aware dependencies. | ||
This is a subsystem because in future the compiler plugin types should be injected | ||
via subsystem or option dependencies rather than declared statically. | ||
""" | ||
|
||
options_scope = 'jvm-dependency-context' | ||
|
||
target_closure_kwargs = dict(include_scopes=Scopes.JVM_COMPILE_SCOPES, respect_intransitive=True) | ||
compiler_plugin_types = (AnnotationProcessor, JavacPlugin, ScalacPlugin) | ||
alias_types = (AliasTarget, Target) | ||
codegen_types = (JavaThriftLibrary, JavaProtobufLibrary) | ||
|
||
@classmethod | ||
def subsystem_dependencies(cls): | ||
return super(DependencyContext, cls).subsystem_dependencies() + (Java, ScalaPlatform) | ||
|
||
def all_dependencies(self, target): | ||
"""All transitive dependencies of the context's target.""" | ||
for dep in target.closure(bfs=True, **self.target_closure_kwargs): | ||
yield dep | ||
|
||
def create_fingerprint_strategy(self, classpath_products): | ||
return ResolvedJarAwareFingerprintStrategy(classpath_products, self) | ||
|
||
def defaulted_property(self, target, selector): | ||
"""Computes a language property setting for the given JvmTarget. | ||
:param selector A function that takes a target or platform and returns the boolean value of the | ||
property for that target or platform, or None if that target or platform does | ||
not directly define the property. | ||
If the target does not override the language property, returns true iff the property | ||
is true for any of the matched languages for the target. | ||
""" | ||
if selector(target) is not None: | ||
return selector(target) | ||
|
||
prop = False | ||
if target.has_sources('.java'): | ||
prop |= selector(Java.global_instance()) | ||
if target.has_sources('.scala'): | ||
prop |= selector(ScalaPlatform.global_instance()) | ||
return prop | ||
|
||
|
||
class ResolvedJarAwareFingerprintStrategy(FingerprintStrategy): | ||
"""Task fingerprint strategy that also includes the resolved coordinates of dependent jars.""" | ||
|
||
def __init__(self, classpath_products, dep_context): | ||
super(ResolvedJarAwareFingerprintStrategy, self).__init__() | ||
self._classpath_products = classpath_products | ||
self._dep_context = dep_context | ||
|
||
def compute_fingerprint(self, target): | ||
if isinstance(target, Resources): | ||
# Just do nothing, this kind of dependency shouldn't affect result's hash. | ||
return None | ||
|
||
hasher = hashlib.sha1() | ||
hasher.update(target.payload.fingerprint()) | ||
if isinstance(target, JarLibrary): | ||
# NB: Collects only the jars for the current jar_library, and hashes them to ensure that both | ||
# the resolved coordinates, and the requested coordinates are used. This ensures that if a | ||
# source file depends on a library with source compatible but binary incompatible signature | ||
# changes between versions, that you won't get runtime errors due to using an artifact built | ||
# against a binary incompatible version resolved for a previous compile. | ||
classpath_entries = self._classpath_products.get_artifact_classpath_entries_for_targets( | ||
[target]) | ||
for _, entry in classpath_entries: | ||
hasher.update(str(entry.coordinate)) | ||
return hasher.hexdigest() | ||
|
||
def direct(self, target): | ||
return self._dep_context.defaulted_property(target, lambda x: x.strict_deps) | ||
|
||
def dependencies(self, target): | ||
if self.direct(target): | ||
return target.strict_dependencies(self._dep_context) | ||
return super(ResolvedJarAwareFingerprintStrategy, self).dependencies(target) | ||
|
||
def __hash__(self): | ||
# NB: FingerprintStrategy requires a useful override of eq/hash. | ||
return hash(type(self)) | ||
|
||
def __eq__(self, other): | ||
# NB: See __hash__. | ||
return type(self) == type(other) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.