Skip to content

Commit

Permalink
Retrieve jars from IvyInfo using a collection of coordinates instead …
Browse files Browse the repository at this point in the history
…of jar_library targets.

Using a target as the parameter type for retrieving jars tightly coupled lookup in ivy reports. This changes the retrieval method so that it accepts coordinate like objects instead.

Testing Done:
Updated tests and ran them locally, CI away on PR.

Bugs closed: 2959

Reviewed at https://rbcommons.com/s/twitter/r/3495/

closes pantsbuild#2959
  • Loading branch information
baroquebobcat committed Feb 25, 2016
1 parent 586c641 commit e556ab8
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 23 deletions.
17 changes: 9 additions & 8 deletions src/python/pants/backend/jvm/ivy_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,18 +175,19 @@ def traverse_dependency_graph(self, ref, collector, memo=None):
visited = set()
return self._do_traverse_dependency_graph(ref, collector, memo, visited)

def get_resolved_jars_for_jar_library(self, jar_library, memo=None):
"""Collects jars for the passed jar_library.
def get_resolved_jars_for_coordinates(self, coordinates, memo=None):
"""Collects jars for the passed coordinates.
Because artifacts are only fetched for the "winning" version of a module, the artifacts
will not always represent the version originally declared by the library.
This method is transitive within the library's jar_dependencies, but will NOT
walk into its non-jar dependencies.
This method is transitive within the passed coordinates dependencies.
:param jar_library A JarLibrary to collect the transitive artifacts for.
:param memo see `traverse_dependency_graph`
:returns: all the artifacts for all of the jars in this library, including transitive deps
:param coordinates collections.Iterable: Collection of coordinates to collect transitive
resolved jars for.
:param memo: See `traverse_dependency_graph`.
:returns: All the artifacts for all of the jars for the provided coordinates,
including transitive dependencies.
:rtype: list of :class:`pants.backend.jvm.jar_dependency_utils.ResolvedJar`
"""
def to_resolved_jar(jar_ref, jar_path):
Expand All @@ -199,7 +200,7 @@ def to_resolved_jar(jar_ref, jar_path):
resolved_jars = OrderedSet()
def create_collection(dep):
return OrderedSet([dep])
for jar in jar_library.jar_dependencies:
for jar in coordinates:
classifier = jar.classifier if self._conf == 'default' else self._conf
jar_module_ref = IvyModuleRef(jar.org, jar.name, jar.rev, classifier)
for module_ref in self.traverse_dependency_graph(jar_module_ref, create_collection, memo):
Expand Down
3 changes: 2 additions & 1 deletion src/python/pants/backend/jvm/tasks/ivy_task_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,8 @@ def candidate_cache_paths():
jar_library_targets = [t for t in targets if isinstance(t, JarLibrary)]
for target in jar_library_targets:
# Add the artifacts from each dependency module.
raw_resolved_jars = ivy_info.get_resolved_jars_for_jar_library(target, memo=ivy_jar_memo)
raw_resolved_jars = ivy_info.get_resolved_jars_for_coordinates(target.jar_dependencies,
memo=ivy_jar_memo)
resolved_jars = [new_resolved_jar_with_symlink_path(target, conf, raw_resolved_jar)
for raw_resolved_jar in raw_resolved_jars]
classpath_products.add_jars_for_targets([target], conf, resolved_jars)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="ivy-report.xsl"?>
<!-- This is emulating the structure of a report created with a fetch resolve. -->
<ivy-report version="1.0">
<info organisation="toplevel" module="toplevelmodule" revision="latest" />
<dependencies>
<module organisation="org1" name="name1">
<revision name="0.0.1">
<caller organisation="toplevel" name="toplevelmodule" callerrev="latest"/>
<artifacts>
<artifact location="ivy2cache_path/org1/name1.jar" extra-classifier="tests"/>
</artifacts>
</revision>
</module>
<module organisation="org2" name="name2">
<revision name="0.0.1">
<caller organisation="toplevel" name="toplevelmodule" callerrev="latest"/>
<artifacts>
<artifact type="bundle" ext="jar" location="ivy2cache_path/org2/name2.jar"/>
</artifacts>
</revision>
</module>
<module organisation="org3" name="name3">
<revision name="0.0.1">
<caller organisation="toplevel" name="toplevelmodule" callerrev="latest"/>
<artifacts>
<artifact type="jar" ext="tar.gz" location="ivy2cache_path/org3/name3.tar.gz"/>
</artifacts>
</revision>
</module>
</dependencies>
</ivy-report>
40 changes: 26 additions & 14 deletions tests/python/pants_test/backend/jvm/tasks/test_ivy_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
from pants.backend.jvm.subsystems.jar_dependency_management import JarDependencyManagement
from pants.backend.jvm.targets.exclude import Exclude
from pants.backend.jvm.targets.jar_dependency import JarDependency
from pants.backend.jvm.targets.jar_library import JarLibrary
from pants.build_graph.register import build_file_aliases as register_core
from pants.ivy.ivy_subsystem import IvySubsystem
from pants.util.contextutil import temporary_dir, temporary_file_path
Expand Down Expand Up @@ -196,14 +195,13 @@ def test_resolve_conflict_conflict(self):
with self.assertRaises(IvyUtils.IvyResolveConflictingDepsError):
IvyUtils._resolve_conflict(v2_force, v1_force)

def test_get_resolved_jars_for_jar_library(self):
def test_get_resolved_jars_for_coordinates(self):
ivy_info = self.parse_ivy_report('ivy_utils_resources/report_with_diamond.xml')
lib = self.make_target(spec=':org1-name1',
target_type=JarLibrary,
jars=[JarDependency(org='org1', name='name1', rev='0.0.1',
classifier='tests')])

resolved_jars = ivy_info.get_resolved_jars_for_jar_library(lib)
resolved_jars = ivy_info.get_resolved_jars_for_coordinates([JarDependency(org='org1',
name='name1',
rev='0.0.1',
classifier='tests')])

expected = {'ivy2cache_path/org1/name1.jar': coord(org='org1', name='name1',
classifier='tests'),
Expand All @@ -216,16 +214,13 @@ def test_get_resolved_jars_for_jar_library(self):
def test_resolved_jars_with_different_version(self):
# If a jar is resolved as a different version than the requested one, the coordinates of
# the resolved jar should match the artifact, not the requested coordinates.
lib = self.make_target(spec=':org1-name1',
target_type=JarLibrary,
jars=[
JarDependency(org='org1', name='name1',
rev='0.0.1',
classifier='tests')])

ivy_info = self.parse_ivy_report('ivy_utils_resources/report_with_resolve_to_other_version.xml')

resolved_jars = ivy_info.get_resolved_jars_for_jar_library(lib)
resolved_jars = ivy_info.get_resolved_jars_for_coordinates([JarDependency(org='org1',
name='name1',
rev='0.0.1',
classifier='tests')])

self.maxDiff = None
self.assertEqual([coord(org='org1', name='name1',
Expand Down Expand Up @@ -295,6 +290,23 @@ def collector(r):
},
result1)

def test_retrieve_resolved_jars_with_coordinates_on_flat_fetch_resolve(self):
ivy_info = self.parse_ivy_report('ivy_utils_resources/report_with_flat_graph.xml')
coordinates = [coord(org='org1', name='name1', classifier='tests', rev='0.0.1')]

result = ivy_info.get_resolved_jars_for_coordinates(coordinates)

self.assertEqual(coordinates, [r.coordinate for r in result])

def test_retrieve_resolved_jars_with_coordinates_differing_on_version_on_flat_fetch_resolve(self):
ivy_info = self.parse_ivy_report('ivy_utils_resources/report_with_flat_graph.xml')
coordinates = [coord(org='org2', name='name2', rev='0.0.0')]

result = ivy_info.get_resolved_jars_for_coordinates(coordinates)

self.assertEqual([coord(org='org2', name='name2', rev='0.0.1')],
[r.coordinate for r in result])

def test_parse_fails_when_same_classifier_different_type(self):
with self.assertRaises(IvyResolveMappingError):
self.parse_ivy_report('ivy_utils_resources/report_with_same_classifier_different_type.xml')
Expand Down

0 comments on commit e556ab8

Please sign in to comment.