Example #1
0
  def _compute_jars_to_resolve_and_pin(raw_jars, artifact_set, manager):
    """
    This method provides settled lists of jar dependencies and coordinates
    based on conflict management.

    :param raw_jars: a collection of `JarDependencies`
    :param artifact_set: PinnedJarArtifactSet
    :param manager: JarDependencyManagement
    :return: (list of settled `JarDependency`, set of pinned `M2Coordinate`)
    """
    if artifact_set is None:
      artifact_set = PinnedJarArtifactSet()

    untouched_pinned_artifact = {M2Coordinate.create(x) for x in artifact_set}
    jar_list = list(raw_jars)
    for i, dep in enumerate(jar_list):
      direct_coord = M2Coordinate.create(dep)
      # Portion to manage pinned jars in case of conflict
      if direct_coord in artifact_set:
        managed_coord = artifact_set[direct_coord]
        untouched_pinned_artifact.remove(managed_coord)

        if direct_coord.rev != managed_coord.rev:
          # It may be necessary to actually change the version number of the jar we want to resolve
          # here, because overrides do not apply directly (they are exclusively transitive). This is
          # actually a good thing, because it gives us more control over what happens.
          coord = manager.resolve_version_conflict(managed_coord, direct_coord, force=dep.force)

          # Once a version is settled, we force it anyway
          jar_list[i] = dep.copy(rev=coord.rev, force=True)

    return jar_list, untouched_pinned_artifact
  def test_m2_string_representation(self):
    org_name_ref = M2Coordinate(org='org.example', name='lib', rev='the-rev')

    self.assertEqual('org.example:lib:the-rev', str(org_name_ref))
    self.assertEqual(org_name_ref, M2Coordinate.from_string(str(org_name_ref)))

    org_name_ref_classifier = M2Coordinate(org='org.example', name='lib',
                                           rev='the-rev', classifier='classify')

    self.assertEqual('org.example:lib:jar:classify:the-rev', str(org_name_ref_classifier))
    self.assertEqual(org_name_ref_classifier, M2Coordinate.from_string(str(org_name_ref_classifier)))

    org_name_classifier = M2Coordinate(org='org.example', name='lib', classifier='classify')

    self.assertEqual('org.example:lib:jar:classify:', str(org_name_classifier))
    self.assertEqual(org_name_classifier, M2Coordinate.from_string(str(org_name_classifier)))

    org_name_type_classifier = M2Coordinate(org='org.example', name='lib',
                                            classifier='classify', ext='zip')

    self.assertEqual('org.example:lib:zip:classify:', str(org_name_type_classifier))
    self.assertEqual(org_name_type_classifier, M2Coordinate.from_string(str(org_name_type_classifier)))

    org_name_type_jar_classifier = M2Coordinate(org='org.example', name='lib',
                                                classifier='classify', ext='jar')

    self.assertEqual('org.example:lib:jar:classify:', str(org_name_type_jar_classifier))
    self.assertEqual(org_name_type_jar_classifier, M2Coordinate.from_string(str(org_name_type_jar_classifier)))
 def handle_target(target):
   if not isinstance(target, ManagedJarDependencies):
     return
   for artifact in handle_managed_jar_dependencies(target):
     if artifact.rev != artifact_set[artifact].rev:
       handle_conflict(artifact, target)
     specs_by_coordinate[M2Coordinate.create(artifact)] = target.address.spec
     artifact_set.put(artifact)
Example #4
0
  def _generate_resolve_ivy(cls, jars, excludes, ivyxml, confs, resolve_hash_name, pinned_artifacts=None,
                    jar_dep_manager=None):
    org = IvyUtils.INTERNAL_ORG_NAME
    name = resolve_hash_name

    extra_configurations = [conf for conf in confs if conf and conf != 'default']

    jars_by_key = OrderedDict()
    for jar in jars:
      jars = jars_by_key.setdefault((jar.org, jar.name), [])
      jars.append(jar)

    manager = jar_dep_manager or JarDependencyManagement.global_instance()
    artifact_set = PinnedJarArtifactSet(pinned_artifacts) # Copy, because we're modifying it.
    for jars in jars_by_key.values():
      for i, dep in enumerate(jars):
        direct_coord = M2Coordinate.create(dep)
        managed_coord = artifact_set[direct_coord]
        if direct_coord.rev != managed_coord.rev:
          # It may be necessary to actually change the version number of the jar we want to resolve
          # here, because overrides do not apply directly (they are exclusively transitive). This is
          # actually a good thing, because it gives us more control over what happens.
          coord = manager.resolve_version_conflict(managed_coord, direct_coord, force=dep.force)
          jars[i] = dep.copy(rev=coord.rev)
        elif dep.force:
          # If this dependency is marked as 'force' and there is no version conflict, use the normal
          # pants behavior for 'force'.
          artifact_set.put(direct_coord)

    dependencies = [cls._generate_jar_template(jars) for jars in jars_by_key.values()]

    # As it turns out force is not transitive - it only works for dependencies pants knows about
    # directly (declared in BUILD files - present in generated ivy.xml). The user-level ivy docs
    # don't make this clear [1], but the source code docs do (see isForce docs) [2]. I was able to
    # edit the generated ivy.xml and use the override feature [3] though and that does work
    # transitively as you'd hope.
    #
    # [1] http://ant.apache.org/ivy/history/2.3.0/settings/conflict-managers.html
    # [2] https://svn.apache.org/repos/asf/ant/ivy/core/branches/2.3.0/
    #     src/java/org/apache/ivy/core/module/descriptor/DependencyDescriptor.java
    # [3] http://ant.apache.org/ivy/history/2.3.0/ivyfile/override.html
    overrides = [cls._generate_override_template(_coord) for _coord in artifact_set]

    excludes = [cls._generate_exclude_template(exclude) for exclude in excludes]

    template_data = TemplateData(
      org=org,
      module=name,
      extra_configurations=extra_configurations,
      dependencies=dependencies,
      excludes=excludes,
      overrides=overrides)

    template_relpath = os.path.join('templates', 'ivy_utils', 'ivy.xml.mustache')
    cls._write_ivy_xml_file(ivyxml, template_data, template_relpath)
  def test_m2_coordinate_create(self):
    attrs = ('org', 'name', 'rev', 'classifier', 'ext')

    class CoordinateLike(object):
      def __init__(self):
        for i, a in enumerate(attrs):
          setattr(self, a, chr(i+ord('a'))) # Set attrs to the first few letters in the alphabet.

    coord = CoordinateLike()
    m2 = M2Coordinate.create(coord)
    self.assertNotEqual(m2, coord)
    self.assertEqual(tuple(getattr(coord, a) for a in attrs),
                      tuple(getattr(m2, a) for a in attrs))
  def put(self, artifact):
    """Adds the given coordinate to the set, using its version to pin it.

    If this set already contains an artifact with the same coordinates other than the version, it is
    replaced by the new artifact.

    :param M2Coordinate artifact: the artifact coordinate.
    """
    artifact = M2Coordinate.create(artifact)
    if artifact.rev is None:
      raise self.MissingVersion('Cannot pin an artifact to version "None"! {}'.format(artifact))
    key = self._key(artifact)
    previous = self._artifacts_to_versions.get(key)
    self._artifacts_to_versions[key] = artifact
    if previous != artifact:
      self._id = None
 def test_m2_coordinate_unversioned_noop(self):
   m2 = M2Coordinate(org='a', name='b', rev=None, classifier='d', ext='e')
   m2_un = M2Coordinate.unversioned(m2) # Should just return the original object.
   self.assertIs(m2, m2_un)
Example #8
0
        def process_target(current_target):
            """
      :type current_target:pants.build_graph.target.Target
      """
            def get_target_type(target):
                if target.is_test:
                    return ExportTask.SourceRootTypes.TEST
                else:
                    if (isinstance(target, Resources)
                            and target in resource_target_map
                            and resource_target_map[target].is_test):
                        return ExportTask.SourceRootTypes.TEST_RESOURCE
                    elif isinstance(target, Resources):
                        return ExportTask.SourceRootTypes.RESOURCE
                    else:
                        return ExportTask.SourceRootTypes.SOURCE

            info = {
                'targets': [],
                'libraries': [],
                'roots': [],
                'id':
                current_target.id,
                'target_type':
                get_target_type(current_target),
                # NB: is_code_gen should be removed when export format advances to 1.1.0 or higher
                'is_code_gen':
                current_target.is_synthetic,
                'is_synthetic':
                current_target.is_synthetic,
                'pants_target_type':
                self._get_pants_target_alias(type(current_target)),
            }

            if not current_target.is_synthetic:
                info['globs'] = current_target.globs_relative_to_buildroot()
                if self.get_options().sources:
                    info['sources'] = list(
                        current_target.sources_relative_to_buildroot())

            info['transitive'] = current_target.transitive
            info['scope'] = str(current_target.scope)
            info['is_target_root'] = current_target in target_roots_set

            if isinstance(current_target, PythonRequirementLibrary):
                reqs = current_target.payload.get_field_value(
                    'requirements', set())
                """:type : set[pants.backend.python.python_requirement.PythonRequirement]"""
                info['requirements'] = [req.key for req in reqs]

            if isinstance(current_target, PythonTarget):
                interpreter_for_target = self.select_interpreter_for_targets(
                    [current_target])
                if interpreter_for_target is None:
                    raise TaskError(
                        'Unable to find suitable interpreter for {}'.format(
                            current_target.address))
                python_interpreter_targets_mapping[
                    interpreter_for_target].append(current_target)
                info['python_interpreter'] = str(
                    interpreter_for_target.identity)

            def iter_transitive_jars(jar_lib):
                """
        :type jar_lib: :class:`pants.backend.jvm.targets.jar_library.JarLibrary`
        :rtype: :class:`collections.Iterator` of
                :class:`pants.java.jar.M2Coordinate`
        """
                if classpath_products:
                    jar_products = classpath_products.get_artifact_classpath_entries_for_targets(
                        (jar_lib, ))
                    for _, jar_entry in jar_products:
                        coordinate = jar_entry.coordinate
                        # We drop classifier and type_ since those fields are represented in the global
                        # libraries dict and here we just want the key into that dict (see `_jar_id`).
                        yield M2Coordinate(org=coordinate.org,
                                           name=coordinate.name,
                                           rev=coordinate.rev)

            target_libraries = OrderedSet()
            if isinstance(current_target, JarLibrary):
                target_libraries = OrderedSet(
                    iter_transitive_jars(current_target))
            for dep in current_target.dependencies:
                info['targets'].append(dep.address.spec)
                if isinstance(dep, JarLibrary):
                    for jar in dep.jar_dependencies:
                        target_libraries.add(
                            M2Coordinate(jar.org, jar.name, jar.rev))
                    # Add all the jars pulled in by this jar_library
                    target_libraries.update(iter_transitive_jars(dep))
                if isinstance(dep, Resources):
                    resource_target_map[dep] = current_target

            if isinstance(current_target, ScalaLibrary):
                for dep in current_target.java_sources:
                    info['targets'].append(dep.address.spec)
                    process_target(dep)

            if isinstance(current_target, JvmTarget):
                info['excludes'] = [
                    self._exclude_id(exclude)
                    for exclude in current_target.excludes
                ]
                info['platform'] = current_target.platform.name
                if hasattr(current_target, 'test_platform'):
                    info['test_platform'] = current_target.test_platform.name

            info['roots'] = map(
                lambda (source_root, package_prefix): {
                    'source_root': source_root,
                    'package_prefix': package_prefix
                }, self._source_roots_for_target(current_target))

            if classpath_products:
                info['libraries'] = [
                    self._jar_id(lib) for lib in target_libraries
                ]
            targets_map[current_target.address.spec] = info
 def test_m2_coordinate_create_noop(self):
   m2 = M2Coordinate(org='a', name='b', rev='c', classifier='d', ext='e')
   m2_new = M2Coordinate.create(m2) # Should just return the original object.
   self.assertIs(m2, m2_new)
Example #10
0
 def to_m2_coord(cls, coord_str, classifier):
   # TODO: currently assuming all packaging is a jar
   return M2Coordinate.from_string(coord_str + ':{}:jar'.format(classifier))
Example #11
0
        def process_target(current_target):
            """
            :type current_target:pants.build_graph.target.Target
            """
            def get_target_type(tgt):
                def is_test(t):
                    return isinstance(t, JUnitTests) or isinstance(
                        t, PythonTests)

                if is_test(tgt):
                    return SourceRootTypes.TEST
                else:
                    if (isinstance(tgt, Resources)
                            and tgt in resource_target_map
                            and is_test(resource_target_map[tgt])):
                        return SourceRootTypes.TEST_RESOURCE
                    elif isinstance(tgt, Resources):
                        return SourceRootTypes.RESOURCE
                    else:
                        return SourceRootTypes.SOURCE

            info = {
                "targets": [],
                "libraries": [],
                "roots": [],
                "id":
                current_target.id,
                "target_type":
                get_target_type(current_target),
                # NB: is_code_gen should be removed when export format advances to 1.1.0 or higher
                "is_code_gen":
                current_target.is_synthetic,
                "is_synthetic":
                current_target.is_synthetic,
                "pants_target_type":
                self._get_pants_target_alias(type(current_target)),
            }

            if not current_target.is_synthetic:
                info["globs"] = current_target.globs_relative_to_buildroot()
                if self.get_options().sources:
                    info["sources"] = list(
                        current_target.sources_relative_to_buildroot())

            info["transitive"] = current_target.transitive
            info["scope"] = str(current_target.scope)
            info["is_target_root"] = current_target in target_roots_set

            if isinstance(current_target, PythonRequirementLibrary):
                reqs = current_target.payload.get_field_value(
                    "requirements", set())
                """:type : set[pants.python.python_requirement.PythonRequirement]"""
                info["requirements"] = [req.key for req in reqs]

            if isinstance(current_target, PythonTarget):
                interpreter_for_target = self._interpreter_cache.select_interpreter_for_targets(
                    [current_target])
                if interpreter_for_target is None:
                    raise TaskError(
                        "Unable to find suitable interpreter for {}".format(
                            current_target.address))
                python_interpreter_targets_mapping[
                    interpreter_for_target].append(current_target)
                info["python_interpreter"] = str(
                    interpreter_for_target.identity)

            def iter_transitive_jars(jar_lib):
                """
                :type jar_lib: :class:`pants.backend.jvm.targets.jar_library.JarLibrary`
                :rtype: :class:`collections.Iterator` of
                        :class:`pants.java.jar.M2Coordinate`
                """
                if classpath_products:
                    jar_products = classpath_products.get_artifact_classpath_entries_for_targets(
                        (jar_lib, ))
                    for _, jar_entry in jar_products:
                        coordinate = jar_entry.coordinate
                        # We drop classifier and type_ since those fields are represented in the global
                        # libraries dict and here we just want the key into that dict (see `_jar_id`).
                        yield M2Coordinate(org=coordinate.org,
                                           name=coordinate.name,
                                           rev=coordinate.rev)

            target_libraries = OrderedSet()
            if isinstance(current_target, JarLibrary):
                target_libraries = OrderedSet(
                    iter_transitive_jars(current_target))
            for dep in current_target.dependencies:
                info["targets"].append(dep.address.spec)
                if isinstance(dep, JarLibrary):
                    for jar in dep.jar_dependencies:
                        target_libraries.add(
                            M2Coordinate(jar.org, jar.name, jar.rev))
                    # Add all the jars pulled in by this jar_library
                    target_libraries.update(iter_transitive_jars(dep))
                if isinstance(dep, Resources):
                    resource_target_map[dep] = current_target

            if isinstance(current_target, ScalaLibrary):
                for dep in current_target.java_sources:
                    info["targets"].append(dep.address.spec)
                    process_target(dep)

            if isinstance(current_target, JvmTarget):
                info["excludes"] = [
                    self._exclude_id(exclude)
                    for exclude in current_target.excludes
                ]
                info["platform"] = current_target.platform.name
                if hasattr(current_target, "runtime_platform"):
                    info[
                        "runtime_platform"] = current_target.runtime_platform.name

            info["roots"] = [{
                "source_root": source_root_package_prefix[0],
                "package_prefix": source_root_package_prefix[1],
            } for source_root_package_prefix in self._source_roots_for_target(
                current_target)]

            if classpath_products:
                info["libraries"] = [
                    self._jar_id(lib) for lib in target_libraries
                ]
            targets_map[current_target.address.spec] = info
Example #12
0
 def m2_for(c):
   return M2Coordinate.from_string(c)
    def resolve_version_conflict(self,
                                 managed_coord,
                                 direct_coord,
                                 force=False):
        """Resolves an artifact version conflict between directly specified and managed jars.

    This uses the user-defined --conflict-strategy to pick the appropriate artifact version (or to
    raise an error).

    This assumes the two conflict coordinates differ only by their version.

    :param M2Coordinate managed_coord: the artifact coordinate as defined by a
      managed_jar_dependencies object.
    :param M2Coordinate direct_coord: the artifact coordinate as defined by a jar_library target.
    :param bool force: Whether the artifact defined by the jar_library() was marked with force=True.
      This is checked only if one of the *_IF_FORCED conflict strategies is being used.
    :return: the coordinate of the artifact that should be resolved.
    :rtype: M2Coordinate
    :raises: JarDependencyManagement.DirectManagedVersionConflict if the versions are different and
      the --conflict-strategy is 'FAIL' (which is the default).
    """
        if M2Coordinate.unversioned(managed_coord) != M2Coordinate.unversioned(
                direct_coord):
            raise ValueError(
                'Illegal arguments passed to resolve_version_conflict: managed_coord and '
                'direct_coord must only differ by their version!\n'
                '  Managed: {}\n  Direct:  {}\n'.format(
                    M2Coordinate.unversioned(managed_coord),
                    M2Coordinate.unversioned(direct_coord),
                ))

        if direct_coord.rev is None or direct_coord.rev == managed_coord.rev:
            return managed_coord

        strategy = self.get_options().conflict_strategy
        message = dedent("""
      An artifact directly specified by a jar_library target has a different version than what
      is specified by managed_jar_dependencies.

        Artifact: jar(org={org}, name={name}, classifier={classifier}, ext={ext})
        Direct version:  {direct}
        Managed version: {managed}
    """).format(
            org=direct_coord.org,
            name=direct_coord.name,
            classifier=direct_coord.classifier,
            ext=direct_coord.ext,
            direct=direct_coord.rev,
            managed=managed_coord.rev,
        )

        if strategy == 'FAIL':
            raise self.DirectManagedVersionConflict(
                '{}\nThis raises an error due to the current --jar-dependency-management-conflict-strategy.'
                .format(message))

        is_silent = self.get_options().suppress_conflict_warnings
        log = logger.debug if is_silent else logger.warn

        if strategy == 'USE_DIRECT':
            log(message)
            log('[{}] Using direct version: {}'.format(strategy, direct_coord))
            return direct_coord

        if strategy == 'USE_DIRECT_IF_FORCED':
            log(message)
            if force:
                log('[{}] Using direct version, because force=True: {}'.format(
                    strategy, direct_coord))
                return direct_coord
            else:
                log('[{}] Using managed version, because force=False: {}'.
                    format(strategy, managed_coord))
                return managed_coord

        if strategy == 'USE_MANAGED':
            log(message)
            log('[{}] Using managed version: {}'.format(
                strategy, managed_coord))
            return managed_coord

        if strategy == 'USE_NEWER':
            newer = max([managed_coord, direct_coord],
                        key=lambda coord: Revision.lenient(coord.rev))
            log(message)
            log('[{}] Using newer version: {}'.format(strategy, newer))
            return newer

        raise TaskError(
            'Unknown value for --conflict-strategy: {}'.format(strategy))
Example #14
0
    def test_resolved_jars_with_same_properties(self):
        jar1 = ResolvedJar(M2Coordinate('org.example', 'lib'), 'path')
        jar2 = ResolvedJar(M2Coordinate('org.example', 'lib'), 'path')

        self.assertEqual(jar1, jar2)
        self.assertEqual(hash(jar1), hash(jar2))
Example #15
0
    def test_resolved_jars_with_differing_cache_paths_not_equal(self):
        jar1 = ResolvedJar(M2Coordinate('org.example', 'lib'), 'path1')
        jar2 = ResolvedJar(M2Coordinate('org.example', 'lib'), 'path2')

        self.assertNotEqual(jar1, jar2)
 def test_put_failure(self):
     set1 = PinnedJarArtifactSet()
     with self.assertRaises(PinnedJarArtifactSet.MissingVersion):
         set1.put(M2Coordinate("hello", "there"))
 def test_lookup_noop(self):
     self.assertEqual(
         M2Coordinate("org", "foo", "1.2"),
         PinnedJarArtifactSet()[M2Coordinate("org", "foo", "1.2")],
     )
class JarDependencyManagementTest(TestBase):

    _coord_any = M2Coordinate("foobar", "foobar")
    _coord_one = M2Coordinate("foobar", "foobar", "1.1")
    _coord_two = M2Coordinate("foobar", "foobar", "1.2")

    def _jar_dependency_management(self, **flags):
        Subsystem.reset()
        options = {
            JarDependencyManagement.options_scope: flags,
        }
        return global_subsystem_instance(JarDependencyManagement,
                                         options=options)

    def test_conflict_strategy_short_circuits(self):
        manager = self._jar_dependency_management(conflict_strategy="FAIL")
        manager.resolve_version_conflict(
            direct_coord=self._coord_any,
            managed_coord=self._coord_one,
        )
        manager.resolve_version_conflict(
            direct_coord=self._coord_one,
            managed_coord=self._coord_one,
        )

    def test_conflict_strategy_fail(self):
        manager = self._jar_dependency_management(conflict_strategy="FAIL")
        with self.assertRaises(
                JarDependencyManagement.DirectManagedVersionConflict):
            manager.resolve_version_conflict(
                direct_coord=self._coord_one,
                managed_coord=self._coord_two,
            )

    def test_conflict_strategy_use_direct(self):
        manager = self._jar_dependency_management(
            conflict_strategy="USE_DIRECT")
        self.assertEqual(
            self._coord_one,
            manager.resolve_version_conflict(
                direct_coord=self._coord_one,
                managed_coord=self._coord_two,
            ),
        )
        manager = self._jar_dependency_management(
            conflict_strategy="USE_DIRECT", suppress_conflict_messages=True)
        self.assertEqual(
            self._coord_one,
            manager.resolve_version_conflict(
                direct_coord=self._coord_one,
                managed_coord=self._coord_two,
            ),
        )

    def test_conflict_strategy_use_managed(self):
        manager = self._jar_dependency_management(
            conflict_strategy="USE_MANAGED")
        self.assertEqual(
            self._coord_two,
            manager.resolve_version_conflict(
                direct_coord=self._coord_one,
                managed_coord=self._coord_two,
            ),
        )
        manager = self._jar_dependency_management(
            conflict_strategy="USE_MANAGED", suppress_conflict_messages=True)
        self.assertEqual(
            self._coord_two,
            manager.resolve_version_conflict(
                direct_coord=self._coord_one,
                managed_coord=self._coord_two,
            ),
        )

    def test_conflict_strategy_use_forced(self):
        manager = self._jar_dependency_management(
            conflict_strategy="USE_DIRECT_IF_FORCED")
        self.assertEqual(
            self._coord_two,
            manager.resolve_version_conflict(
                direct_coord=self._coord_one,
                managed_coord=self._coord_two,
            ),
        )
        self.assertEqual(
            self._coord_one,
            manager.resolve_version_conflict(
                direct_coord=self._coord_one,
                managed_coord=self._coord_two,
                force=True,
            ),
        )

    def test_conflict_strategy_use_newer(self):
        manager = self._jar_dependency_management(
            conflict_strategy="USE_NEWER")
        self.assertEqual(
            self._coord_two,
            manager.resolve_version_conflict(
                direct_coord=self._coord_one,
                managed_coord=self._coord_two,
            ),
        )
        self.assertEqual(
            self._coord_two,
            manager.resolve_version_conflict(
                direct_coord=self._coord_two,
                managed_coord=self._coord_one,
            ),
        )

    def test_conflict_resolution_input_validation(self):
        manager = self._jar_dependency_management()
        with self.assertRaises(ValueError):
            manager.resolve_version_conflict(M2Coordinate("org", "foo", "1.2"),
                                             M2Coordinate("com", "bar", "7.8"))
        with self.assertRaises(ValueError):
            manager.resolve_version_conflict(M2Coordinate("org", "foo", "1.2"),
                                             M2Coordinate("com", "bar", "1.2"))
Example #19
0
 def m2_for(c):
   return M2Coordinate.from_string(c)
Example #20
0
    def test_create_canonical_classpath(self):
        a = self.make_target("a/b", JvmTarget)

        jar_path = "ivy/jars/org.x/lib/x-1.0.jar"
        classpath_products = ClasspathProducts(self.pants_workdir)

        resolved_jar = ResolvedJar(
            M2Coordinate(org="org", name="x", rev="1.0"),
            cache_path="somewhere",
            pants_path=self._create_file(jar_path),
        )

        classpath_products.add_for_target(
            a,
            [("default", self._create_file("a.jar")),
             ("default", self._create_file("resources"))],
        )
        classpath_products.add_jars_for_targets([a], "default", [resolved_jar])

        with temporary_dir() as base_dir:
            self._test_canonical_classpath_helper(
                classpath_products,
                [a],
                base_dir,
                ["a.b.b-0.jar", "a.b.b-1", "a.b.b-2.jar"],
                {
                    "a.b.b-classpath.txt":
                    "{}/a.jar:{}/resources:{}/{}\n".format(
                        self.pants_workdir, self.pants_workdir,
                        self.pants_workdir, jar_path)
                },
                excludes={Exclude(org="org", name="y")},
            )

        # incrementally delete the resource dependency
        classpath_products = ClasspathProducts(self.pants_workdir)
        classpath_products.add_for_target(
            a, [("default", self._create_file("a.jar"))])
        self._test_canonical_classpath_helper(
            classpath_products,
            [a],
            base_dir,
            ["a.b.b-0.jar"],
            {"a.b.b-classpath.txt": f"{self.pants_workdir}/a.jar\n"},
        )

        # incrementally add another jar dependency
        classpath_products = ClasspathProducts(self.pants_workdir)
        classpath_products.add_for_target(
            a, [("default", self._create_file("a.jar")),
                ("default", self._create_file("b.jar"))])
        self._test_canonical_classpath_helper(
            classpath_products,
            [a],
            base_dir,
            ["a.b.b-0.jar", "a.b.b-1.jar"],
            {
                "a.b.b-classpath.txt":
                "{}/a.jar:{}/b.jar\n".format(self.pants_workdir,
                                             self.pants_workdir)
            },
        )
Example #21
0
def resolved_example_jar_at(path, org="com.example", name="lib"):
    return ResolvedJar(
        M2Coordinate(org=org, name=name),
        cache_path=os.path.join("resolver-cache-dir", path),
        pants_path=path,
    )
Example #22
0
 def test_m2_coordinate_create_noop(self):
     m2 = M2Coordinate(org='a', name='b', rev='c', classifier='d', ext='e')
     m2_new = M2Coordinate.create(
         m2)  # Should just return the original object.
     self.assertIs(m2, m2_new)
Example #23
0
    def test_m2_coordinate_artifact_path_explicit_ext(self):
        coordinate = M2Coordinate('org.example', 'lib', '1.0.0', ext='tar.gz')

        self.assertEqual('org.example-lib-1.0.0.tar.gz',
                         coordinate.artifact_filename)
Example #24
0
 def test_m2_coordinate_unversioned_noop(self):
     m2 = M2Coordinate(org='a', name='b', rev=None, classifier='d', ext='e')
     m2_un = M2Coordinate.unversioned(
         m2)  # Should just return the original object.
     self.assertIs(m2, m2_un)
Example #25
0
class JarDependencyManagementTest(BaseTest):

    _coord_any = M2Coordinate('foobar', 'foobar')
    _coord_one = M2Coordinate('foobar', 'foobar', '1.1')
    _coord_two = M2Coordinate('foobar', 'foobar', '1.2')

    def _jar_dependency_management(self, **flags):
        Subsystem.reset()
        options = {
            JarDependencyManagement.options_scope: flags,
        }
        return global_subsystem_instance(JarDependencyManagement,
                                         options=options)

    def test_conflict_strategy_short_circuits(self):
        manager = self._jar_dependency_management(conflict_strategy='FAIL')
        manager.resolve_version_conflict(
            direct_coord=self._coord_any,
            managed_coord=self._coord_one,
        )
        manager.resolve_version_conflict(
            direct_coord=self._coord_one,
            managed_coord=self._coord_one,
        )

    def test_conflict_strategy_fail(self):
        manager = self._jar_dependency_management(conflict_strategy='FAIL')
        with self.assertRaises(
                JarDependencyManagement.DirectManagedVersionConflict):
            manager.resolve_version_conflict(
                direct_coord=self._coord_one,
                managed_coord=self._coord_two,
            )

    def test_conflict_strategy_use_direct(self):
        manager = self._jar_dependency_management(
            conflict_strategy='USE_DIRECT')
        self.assertEquals(
            self._coord_one,
            manager.resolve_version_conflict(
                direct_coord=self._coord_one,
                managed_coord=self._coord_two,
            ))
        manager = self._jar_dependency_management(
            conflict_strategy='USE_DIRECT', suppress_conflict_messages=True)
        self.assertEquals(
            self._coord_one,
            manager.resolve_version_conflict(
                direct_coord=self._coord_one,
                managed_coord=self._coord_two,
            ))

    def test_conflict_strategy_use_managed(self):
        manager = self._jar_dependency_management(
            conflict_strategy='USE_MANAGED')
        self.assertEquals(
            self._coord_two,
            manager.resolve_version_conflict(
                direct_coord=self._coord_one,
                managed_coord=self._coord_two,
            ))
        manager = self._jar_dependency_management(
            conflict_strategy='USE_MANAGED', suppress_conflict_messages=True)
        self.assertEquals(
            self._coord_two,
            manager.resolve_version_conflict(
                direct_coord=self._coord_one,
                managed_coord=self._coord_two,
            ))

    def test_conflict_strategy_use_forced(self):
        manager = self._jar_dependency_management(
            conflict_strategy='USE_DIRECT_IF_FORCED')
        self.assertEquals(
            self._coord_two,
            manager.resolve_version_conflict(
                direct_coord=self._coord_one,
                managed_coord=self._coord_two,
            ))
        self.assertEquals(
            self._coord_one,
            manager.resolve_version_conflict(
                direct_coord=self._coord_one,
                managed_coord=self._coord_two,
                force=True,
            ))

    def test_conflict_strategy_use_newer(self):
        manager = self._jar_dependency_management(
            conflict_strategy='USE_NEWER')
        self.assertEquals(
            self._coord_two,
            manager.resolve_version_conflict(
                direct_coord=self._coord_one,
                managed_coord=self._coord_two,
            ))
        self.assertEquals(
            self._coord_two,
            manager.resolve_version_conflict(
                direct_coord=self._coord_two,
                managed_coord=self._coord_one,
            ))

    def test_conflict_resolution_input_validation(self):
        manager = self._jar_dependency_management()
        with self.assertRaises(ValueError):
            manager.resolve_version_conflict(M2Coordinate('org', 'foo', '1.2'),
                                             M2Coordinate('com', 'bar', '7.8'))
        with self.assertRaises(ValueError):
            manager.resolve_version_conflict(M2Coordinate('org', 'foo', '1.2'),
                                             M2Coordinate('com', 'bar', '1.2'))
Example #26
0
 def test_m2_coordinate_unversioned(self):
     m2 = M2Coordinate(org='a', name='b', rev='c', classifier='d', ext='e')
     m2_un = M2Coordinate.unversioned(m2)
     self.assertNotEqual(m2, m2_un)
     self.assertTrue(m2_un.rev is None)
Example #27
0
def resolved_example_jar_at(path, org='com.example', name='lib'):
    return ResolvedJar(M2Coordinate(org=org, name=name),
                       cache_path=os.path.join('resolver-cache-dir', path),
                       pants_path=path)
Example #28
0
    def test_m2_coordinates_with_same_properties(self):
        coordinate1 = M2Coordinate('org.example', 'lib')
        coordinate2 = M2Coordinate('org.example', 'lib')

        self.assertEqual(coordinate1, coordinate2)
        self.assertEqual(hash(coordinate1), hash(coordinate2))
Example #29
0
 def to_m2_coord(cls, coord_str):
   return M2Coordinate.from_string(coord_str)
 def test_m2_coordinate_unversioned(self):
   m2 = M2Coordinate(org='a', name='b', rev='c', classifier='d', ext='e')
   m2_un = M2Coordinate.unversioned(m2)
   self.assertNotEqual(m2, m2_un)
   self.assertTrue(m2_un.rev is None)
 def to_m2_coord(cls, coord_str):
     return M2Coordinate.from_string(coord_str)
Example #32
0
 def test_lookup_noop(self):
     self.assertEquals(
         M2Coordinate('org', 'foo', '1.2'),
         PinnedJarArtifactSet()[M2Coordinate('org', 'foo', '1.2')])
Example #33
0
def coord(org, name, classifier=None, rev=None, ext=None):
  rev = rev or '0.0.1'
  return M2Coordinate(org=org, name=name, rev=rev, classifier=classifier, ext=ext)
Example #34
0
    def test_m2_coordinate_artifact_path_classifier(self):
        coordinate = M2Coordinate("org.example", "lib", "1.0.0", "sources")

        self.assertEqual("org.example-lib-1.0.0-sources.jar",
                         coordinate.artifact_filename)
Example #35
0
    def test_m2_coordinate_artifact_path_explicit_ext(self):
        coordinate = M2Coordinate("org.example", "lib", "1.0.0", ext="tar.gz")

        self.assertEqual("org.example-lib-1.0.0.tar.gz",
                         coordinate.artifact_filename)
Example #36
0
    def test_m2_coordinate_artifact_path_classifier(self):
        coordinate = M2Coordinate('org.example', 'lib', '1.0.0', 'sources')

        self.assertEqual('org.example-lib-1.0.0-sources.jar',
                         coordinate.artifact_filename)
Example #37
0
    def test_m2_coordinates_with_differing_properties_not_equal(self):
        coordinate1 = M2Coordinate('org.example', 'lib')
        coordinate2 = M2Coordinate('org.example', 'lib2')

        self.assertNotEqual(coordinate1, coordinate2)
Example #38
0
 def _make_coord(self, rev):
     return M2Coordinate(org='com.example', name='bar', rev=rev)
Example #39
0
    def test_m2_coordinates_with_different_types_have_different_hashes(self):
        coordinate1 = M2Coordinate('org.example', 'lib', ext='zip')
        coordinate2 = M2Coordinate('org.example', 'lib')

        self.assertNotEqual(hash(coordinate1), hash(coordinate2))
Example #40
0
    def test_m2_coordinate_artifact_path_no_rev(self):
        coordinate = M2Coordinate('org.example', 'lib')

        self.assertEqual('org.example-lib.jar', coordinate.artifact_filename)
  def resolve_version_conflict(self, managed_coord, direct_coord, force=False):
    """Resolves an artifact version conflict between directly specified and managed jars.

    This uses the user-defined --conflict-strategy to pick the appropriate artifact version (or to
    raise an error).

    This assumes the two conflict coordinates differ only by their version.

    :param M2Coordinate managed_coord: the artifact coordinate as defined by a
      managed_jar_dependencies object.
    :param M2Coordinate direct_coord: the artifact coordinate as defined by a jar_library target.
    :param bool force: Whether the artifact defined by the jar_library() was marked with force=True.
      This is checked only if one of the *_IF_FORCED conflict strategies is being used.
    :return: the coordinate of the artifact that should be resolved.
    :rtype: M2Coordinate
    :raises: JarDependencyManagement.DirectManagedVersionConflict if the versions are different and
      the --conflict-strategy is 'FAIL' (which is the default).
    """
    if M2Coordinate.unversioned(managed_coord) != M2Coordinate.unversioned(direct_coord):
      raise ValueError('Illegal arguments passed to resolve_version_conflict: managed_coord and '
                       'direct_coord must only differ by their version!\n'
                       '  Managed: {}\n  Direct:  {}\n'.format(
        M2Coordinate.unversioned(managed_coord),
        M2Coordinate.unversioned(direct_coord),
      ))

    if direct_coord.rev is None or direct_coord.rev == managed_coord.rev:
      return managed_coord

    strategy = self.get_options().conflict_strategy
    message = dedent("""
      An artifact directly specified by a jar_library target has a different version than what
      is specified by managed_jar_dependencies.

        Artifact: jar(org={org}, name={name}, classifier={classifier}, ext={ext})
        Direct version:  {direct}
        Managed version: {managed}
    """).format(
      org=direct_coord.org,
      name=direct_coord.name,
      classifier=direct_coord.classifier,
      ext=direct_coord.ext,
      direct=direct_coord.rev,
      managed=managed_coord.rev,
    )

    if strategy == 'FAIL':
      raise self.DirectManagedVersionConflict(
        '{}\nThis raises an error due to the current --jar-dependency-management-conflict-strategy.'
        .format(message)
      )

    is_silent = self.get_options().suppress_conflict_warnings
    log = logger.debug if is_silent else logger.warn

    if strategy == 'USE_DIRECT':
      log(message)
      log('[{}] Using direct version: {}'.format(strategy, direct_coord))
      return direct_coord

    if strategy == 'USE_DIRECT_IF_FORCED':
      log(message)
      if force:
        log('[{}] Using direct version, because force=True: {}'.format(strategy, direct_coord))
        return direct_coord
      else:
        log('[{}] Using managed version, because force=False: {}'.format(strategy, managed_coord))
        return managed_coord

    if strategy == 'USE_MANAGED':
      log(message)
      log('[{}] Using managed version: {}'.format(strategy, managed_coord))
      return managed_coord

    if strategy == 'USE_NEWER':
      newer = max([managed_coord, direct_coord],
                  key=lambda coord: Revision.lenient(coord.rev))
      log(message)
      log('[{}] Using newer version: {}'.format(strategy, newer))
      return newer

    raise TaskError('Unknown value for --conflict-strategy: {}'.format(strategy))
Example #42
0
    def test_m2_coordinate_artifact_path_no_rev(self):
        coordinate = M2Coordinate("org.example", "lib")

        self.assertEqual("org.example-lib.jar", coordinate.artifact_filename)