forked from pantsbuild/pants
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
A contrib plugin to run the Kythe indexer on Java source. (pantsbuild…
- Loading branch information
Showing
26 changed files
with
367 additions
and
12 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
Empty file.
Empty file.
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,13 @@ | ||
# Copyright 2017 Pants project contributors (see CONTRIBUTORS.md). | ||
# Licensed under the Apache License, Version 2.0 (see LICENSE). | ||
|
||
contrib_plugin( | ||
name='plugin', | ||
dependencies=[ | ||
'contrib/kythe/src/python/pants/contrib/kythe/tasks', | ||
'src/python/pants/goal:task_registrar', | ||
], | ||
distribution_name='pantsbuild.pants.contrib.kythe', | ||
description='Kythe support for pants.', | ||
register_goals=True, | ||
) |
Empty file.
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,16 @@ | ||
# coding=utf-8 | ||
# Copyright 2017 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) | ||
|
||
from pants.goal.task_registrar import TaskRegistrar as task | ||
|
||
from pants.contrib.kythe.tasks.extract_java import ExtractJava | ||
from pants.contrib.kythe.tasks.index_java import IndexJava | ||
|
||
|
||
def register_goals(): | ||
task(name='extract', action=ExtractJava).install('kythe') | ||
task(name='index', action=IndexJava).install('kythe') |
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,13 @@ | ||
# Copyright 2017 Pants project contributors (see CONTRIBUTORS.md). | ||
# Licensed under the Apache License, Version 2.0 (see LICENSE). | ||
|
||
python_library( | ||
dependencies=[ | ||
'src/python/pants/backend/jvm/subsystems:shader', | ||
'src/python/pants/backend/jvm/targets:jvm', | ||
'src/python/pants/backend/jvm/tasks:jvm_tool_task_mixin', | ||
'src/python/pants/base:exceptions', | ||
'src/python/pants/build_graph', | ||
'src/python/pants/java/jar', | ||
] | ||
) |
Empty file.
113 changes: 113 additions & 0 deletions
113
contrib/kythe/src/python/pants/contrib/kythe/tasks/extract_java.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,113 @@ | ||
# coding=utf-8 | ||
# Copyright 2017 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 os | ||
|
||
from pants.backend.jvm.subsystems.jvm import JVM | ||
from pants.backend.jvm.subsystems.shader import Shader | ||
from pants.backend.jvm.tasks.jvm_tool_task_mixin import JvmToolTaskMixin | ||
from pants.base.exceptions import TaskError | ||
|
||
from pants.contrib.kythe.tasks.indexable_java_targets import IndexableJavaTargets | ||
|
||
|
||
# Kythe requires various system properties to be set (sigh). So we can't use nailgun. | ||
class ExtractJava(JvmToolTaskMixin): | ||
_KYTHE_EXTRACTOR_MAIN = 'com.google.devtools.kythe.extractors.java.standalone.Javac8Wrapper' | ||
|
||
cache_target_dirs = True | ||
|
||
@classmethod | ||
def implementation_version(cls): | ||
# Bump this version to invalidate all past artifacts generated by this task. | ||
return super(ExtractJava, cls).implementation_version() + [('KytheExtract', 6), ] | ||
|
||
@classmethod | ||
def subsystem_dependencies(cls): | ||
return super(ExtractJava, cls).subsystem_dependencies() + (JVM.scoped(cls),) | ||
|
||
@classmethod | ||
def product_types(cls): | ||
# TODO: Support indexpack files? | ||
return ['kindex_files'] | ||
|
||
@classmethod | ||
def prepare(cls, options, round_manager): | ||
super(ExtractJava, cls).prepare(options, round_manager) | ||
round_manager.require_data('runtime_classpath') | ||
round_manager.require_data('zinc_args') | ||
|
||
@classmethod | ||
def register_options(cls, register): | ||
super(ExtractJava, cls).register_options(register) | ||
cls.register_jvm_tool(register, | ||
'kythe-extractor', | ||
custom_rules=[ | ||
# These need to remain unshaded so that Kythe can interact with the | ||
# javac embedded in its jar. | ||
Shader.exclude_package('com.sun', recursive=True), | ||
], | ||
main=cls._KYTHE_EXTRACTOR_MAIN) | ||
|
||
def execute(self): | ||
indexable_targets = IndexableJavaTargets.get(self.context) | ||
targets_to_zinc_args = self.context.products.get_data('zinc_args') | ||
|
||
with self.invalidated(indexable_targets, invalidate_dependents=True) as invalidation_check: | ||
cp = self.tool_classpath('kythe-extractor') | ||
for vt in invalidation_check.invalid_vts: | ||
self.context.log.info('Kythe extracting from {}\n'.format(vt.target.address.spec)) | ||
javac_args = self._get_javac_args_from_zinc_args(targets_to_zinc_args[vt.target]) | ||
jvm_options = list(JVM.scoped_instance(self).get_jvm_options()) | ||
jvm_options.extend([ | ||
'-DKYTHE_CORPUS={}'.format(vt.target.address.spec), | ||
'-DKYTHE_ROOT_DIRECTORY={}'.format(vt.target.target_base), | ||
'-DKYTHE_OUTPUT_DIRECTORY={}'.format(vt.results_dir) | ||
]) | ||
|
||
result = self.dist.execute_java( | ||
classpath=cp, main=self._KYTHE_EXTRACTOR_MAIN, | ||
jvm_options=jvm_options, args=javac_args, workunit_name='kythe-extract') | ||
if result != 0: | ||
raise TaskError('java {main} ... exited non-zero ({result})'.format( | ||
main=self._KYTHE_EXTRACTOR_MAIN, result=result)) | ||
|
||
for vt in invalidation_check.all_vts: | ||
created_files = os.listdir(vt.results_dir) | ||
if len(created_files) != 1: | ||
raise TaskError('Expected a single .kindex file in {}. Got: {}.'.format( | ||
vt.results_dir, ', '.join(created_files) if created_files else 'none')) | ||
kindex_files = self.context.products.get_data('kindex_files', dict) | ||
kindex_files[vt.target] = os.path.join(vt.results_dir, created_files[0]) | ||
|
||
@staticmethod | ||
def _get_javac_args_from_zinc_args(zinc_args): | ||
javac_args = [] | ||
i = iter(zinc_args) | ||
arg = next(i, None) | ||
output_dir = None | ||
while arg is not None: | ||
arg = arg.strip() | ||
if arg in ['-d', '-cp', '-classpath']: | ||
# These are passed through from zinc to javac. | ||
javac_args.append(arg) | ||
javac_args.append(next(i)) | ||
if arg == '-d': | ||
output_dir = javac_args[-1] | ||
elif arg.startswith('-C'): | ||
javac_args.append(arg[2:]) | ||
elif arg.endswith('.java'): | ||
javac_args.append(arg) | ||
arg = next(i, None) | ||
# Strip output dir from classpaths. If we don't then javac will read annotation definitions | ||
# from there instead of from the source files, which will cause the vnames to reflect the .class | ||
# file instead of the .java file. | ||
if output_dir: | ||
for i, a in enumerate(javac_args): | ||
if a in ['-cp', '-classpath']: | ||
javac_args[i + 1] = ':'.join([p for p in javac_args[i + 1].split(':') if p != output_dir]) | ||
return javac_args |
72 changes: 72 additions & 0 deletions
72
contrib/kythe/src/python/pants/contrib/kythe/tasks/index_java.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,72 @@ | ||
# coding=utf-8 | ||
# Copyright 2017 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 os | ||
|
||
from pants.backend.jvm.tasks.nailgun_task import NailgunTask | ||
from pants.base.exceptions import TaskError | ||
from pants.base.workunit import WorkUnitLabel | ||
|
||
from pants.contrib.kythe.tasks.indexable_java_targets import IndexableJavaTargets | ||
|
||
|
||
class IndexJava(NailgunTask): | ||
_KYTHE_INDEXER_MAIN = 'com.google.devtools.kythe.analyzers.java.JavaIndexer' | ||
|
||
cache_target_dirs = True | ||
|
||
@classmethod | ||
def implementation_version(cls): | ||
# Bump this version to invalidate all past artifacts generated by this task. | ||
return super(IndexJava, cls).implementation_version() + [('IndexJava', 6), ] | ||
|
||
@classmethod | ||
def product_types(cls): | ||
return ['kythe_entries_files'] | ||
|
||
@classmethod | ||
def prepare(cls, options, round_manager): | ||
super(IndexJava, cls).prepare(options, round_manager) | ||
round_manager.require_data('kindex_files') | ||
|
||
@classmethod | ||
def register_options(cls, register): | ||
super(IndexJava, cls).register_options(register) | ||
register('--force', type=bool, fingerprint=True, | ||
help='Re-index all targets, even if they are valid.') | ||
cls.register_jvm_tool(register, | ||
'kythe-indexer', | ||
main=cls._KYTHE_INDEXER_MAIN) | ||
|
||
def execute(self): | ||
def entries_file(_vt): | ||
return os.path.join(_vt.results_dir, 'index.entries') | ||
|
||
indexable_targets = IndexableJavaTargets.get(self.context) | ||
|
||
with self.invalidated(indexable_targets, invalidate_dependents=True) as invalidation_check: | ||
kindex_files = self.context.products.get_data('kindex_files') | ||
cp = self.tool_classpath('kythe-indexer') | ||
vts_to_index = (invalidation_check.all_vts if self.get_options().force | ||
else invalidation_check.invalid_vts) | ||
|
||
for vt in vts_to_index: | ||
self.context.log.info('Kythe indexing {}'.format(vt.target.address.spec)) | ||
kindex_file = kindex_files.get(vt.target) | ||
if not kindex_file: | ||
raise TaskError('No .kindex file found for {}'.format(vt.target.address.spec)) | ||
args = [kindex_file, '--out', entries_file(vt)] | ||
result = self.runjava(classpath=cp, main=self._KYTHE_INDEXER_MAIN, | ||
jvm_options=self.get_options().jvm_options, | ||
args=args, workunit_name='kythe-index', | ||
workunit_labels=[WorkUnitLabel.COMPILER]) | ||
if result != 0: | ||
raise TaskError('java {main} ... exited non-zero ({result})'.format( | ||
main=self._KYTHE_INDEXER_MAIN, result=result)) | ||
|
||
for vt in invalidation_check.all_vts: | ||
self.context.products.get_data('kythe_entries_files', dict)[vt.target] = entries_file(vt) |
30 changes: 30 additions & 0 deletions
30
contrib/kythe/src/python/pants/contrib/kythe/tasks/indexable_java_targets.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,30 @@ | ||
# coding=utf-8 | ||
# Copyright 2017 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) | ||
|
||
from pants.backend.jvm.targets.jvm_target import JvmTarget | ||
from pants.build_graph.target_scopes import Scopes | ||
|
||
|
||
class IndexableJavaTargets(object): | ||
"""Determines which java targets Kythe should act on.""" | ||
|
||
@classmethod | ||
def get(cls, context): | ||
"""Return the indexable targets in the given context. | ||
Computes them lazily from the given context. They are then fixed for the duration | ||
of the run, even if this method is called again with a different context. | ||
""" | ||
if not cls._targets: | ||
# TODO: Should we index COMPILE scoped deps? E.g., annotations? | ||
cls._targets = context.targets( | ||
lambda t: isinstance(t, JvmTarget) and t.has_sources('.java'), | ||
exclude_scopes=Scopes.COMPILE | ||
) | ||
return cls._targets | ||
|
||
_targets = None |
Empty file.
Empty file.
Empty file.
13 changes: 13 additions & 0 deletions
13
contrib/kythe/tests/python/pants_test/contrib/kythe/tasks/BUILD
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,13 @@ | ||
# Copyright 2017 Pants project contributors (see CONTRIBUTORS.md). | ||
# Licensed under the Apache License, Version 2.0 (see LICENSE). | ||
|
||
|
||
python_tests( | ||
name = 'integration', | ||
sources = globs('*_integration.py'), | ||
dependencies=[ | ||
'tests/python/pants_test:int-test', | ||
], | ||
tags={'integration'}, | ||
timeout=180, | ||
) |
Empty file.
36 changes: 36 additions & 0 deletions
36
contrib/kythe/tests/python/pants_test/contrib/kythe/tasks/test_index_java_integration.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,36 @@ | ||
# coding=utf-8 | ||
# Copyright 2015 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 glob | ||
import os | ||
|
||
from pants_test.pants_run_integration_test import PantsRunIntegrationTest | ||
|
||
|
||
class TestIndexJavaIntegration(PantsRunIntegrationTest): | ||
def test_index_simple_java_code(self): | ||
# Very simple test that we can run the extractor and indexer on some | ||
# fairly trivial code without crashing, and that we produce something. | ||
args = ['kythe', 'examples/src/java/org/pantsbuild/example/hello::'] | ||
with self.temporary_workdir() as workdir: | ||
pants_run = self.run_pants_with_workdir(args, workdir) | ||
self.assert_success(pants_run) | ||
for tgt in ['examples.src.java.org.pantsbuild.example.hello.greet.greet', | ||
'examples.src.java.org.pantsbuild.example.hello.main.main-bin', | ||
'examples.src.java.org.pantsbuild.example.hello.simple.simple']: | ||
kindex_glob = os.path.join(workdir, | ||
'kythe/extract/current/{}/current/*.kindex'.format(tgt)) | ||
kindex_files = glob.glob(kindex_glob) | ||
self.assertEquals(1, len(kindex_files)) | ||
kindex_file = kindex_files[0] | ||
self.assertTrue(os.path.isfile(kindex_file)) | ||
self.assertGreater(os.path.getsize(kindex_file), 200) # Make sure it's not trivial. | ||
|
||
entries_path = os.path.join(workdir, | ||
'kythe/index/current/{}/current/index.entries'.format(tgt)) | ||
self.assertTrue(os.path.isfile(entries_path)) | ||
self.assertGreater(os.path.getsize(entries_path), 1000) # Make sure it's not trivial. |
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.