示例#1
0
  def test_create_canonical_classpath_with_common_prefix(self):
    """
    A special case when two targets' canonical classpath share a common prefix.

    Until we use `target.id` for canonical classpath, today's implementation is error-prone.
    This is such a regression test case added for a bug discovered in
    https://github.com/pantsbuild/pants/pull/2664

    TODO(peiyu) Remove once we fully migrate to use `target.id`.
    """
    # a and c' canonical classpath share a common prefix: a/b/b
    a = self.make_target('a/b', JvmTarget)
    c = self.make_target('a/b/b/c', JvmTarget)

    classpath_products = ClasspathProducts(self.pants_workdir)

    classpath_products.add_for_target(a, [('default', self._path('a.jar'))])
    classpath_products.add_for_target(c, [('default', self._path('c.jar'))])

    # target c first to verify its first created canonical classpath is preserved
    self._test_canonical_classpath_helper(classpath_products, [c, a],
                                          [
                                            'a/b/b/c/c/0-c.jar',
                                            'a/b/b/0-a.jar',
                                          ],
                                          {
                                            'a/b/b/classpath.txt':
                                              '{}/a.jar\n'.format(self.pants_workdir),
                                            'a/b/b/c/c/classpath.txt':
                                              '{}/c.jar\n'.format(self.pants_workdir),
                                          },
                                          False)
  def test_create_canonical_classpath_no_duplicate_entry(self):
    """Test no more than one symlink are created for the same classpath entry."""
    jar_path = 'ivy/jars/org.x/lib/x-1.0.jar'
    resolved_jar = ResolvedJar(M2Coordinate(org='org', name='x', rev='1.0'),
                               cache_path='somewhere',
                               pants_path=self._create_file(jar_path))
    target_a = self.make_target('a', JvmTarget)
    target_b = self.make_target('b', JvmTarget)

    classpath_products = ClasspathProducts(self.pants_workdir)
    # Both target a and target b depend on the same jar library
    classpath_products.add_jars_for_targets([target_a], 'default', [resolved_jar])
    classpath_products.add_jars_for_targets([target_b], 'default', [resolved_jar])

    with temporary_dir() as base_dir:
      # Only target a generates symlink to jar library, target b skips creating the
      # symlink for the same jar library. Both targets' classpath.txt files should
      # still contain the jar library.
      self._test_canonical_classpath_helper(classpath_products,
                                            [target_a, target_b],
                                            base_dir,
                                            ['a.a-0.jar'],
                                            {
                                              'a.a-classpath.txt':
                                                '{}/{}\n'.format(self.pants_workdir, jar_path),
                                              'b.b-classpath.txt':
                                                '{}/{}\n'.format(self.pants_workdir, jar_path),
                                            })
示例#3
0
  def execute(self):
    jar_import_products = self.context.products.get_data(JarImportProducts,
                                                         init_func=JarImportProducts)

    # Gather all targets that are both capable of importing jars and actually declare some imports.
    targets = self.context.targets(predicate=self.has_imports)
    if not targets:
      return

    # Create a list of all of these targets plus the list of JarDependencies they depend on.
    all_targets = set(targets)
    for target in targets:
      all_targets.update(target.imported_targets)

    imports_classpath = ClasspathProducts(self.get_options().pants_workdir)
    self.resolve(executor=self.create_java_executor(),
                 targets=all_targets,
                 classpath_products=imports_classpath,
                 invalidate_dependents=True)

    for target in targets:
      cp_entries = imports_classpath.get_classpath_entries_for_targets(target.closure(bfs=True))
      for conf, cp_entry in cp_entries:
        if isinstance(cp_entry, ArtifactClasspathEntry):
          jar_import_products.imported(target, cp_entry.coordinate, cp_entry.path)
  def test_single_classpath_element_no_excludes(self):
    a = self.make_target('a', JvmTarget)

    classpath_product = ClasspathProducts()
    path = os.path.join(self.build_root, 'jar/path')
    self.add_jar_classpath_element_for_path(classpath_product, a, path)

    self.assertEqual([('default', path)], classpath_product.get_for_target(a))
  def test_single_classpath_element_no_excludes(self):
    a = self.make_target('a', JvmTarget)

    classpath_product = ClasspathProducts(self.pants_workdir)
    path = self.path('jar/path')
    self.add_jar_classpath_element_for_path(classpath_product, a, path)

    self.assertEqual([('default', path)], classpath_product.get_for_target(a))
  def test_fails_if_paths_outside_buildroot(self):
    a = self.make_target('a', JvmTarget)

    classpath_product = ClasspathProducts()
    with self.assertRaises(TaskError) as cm:
      classpath_product.add_for_target(a, [('default', '/dev/null')])

    self.assertEqual(
      'Classpath entry /dev/null for target a:a is located outside the buildroot.',
      str(cm.exception))
  def test_fails_if_jar_paths_outside_buildroot(self):
    a = self.make_target('a', JvmTarget)

    classpath_product = ClasspathProducts(self.pants_workdir)
    with self.assertRaises(TaskError) as cm:
      classpath_product.add_jars_for_targets([a], 'default', [(resolved_example_jar_at('/dev/null'))])

    self.assertEqual(
      'Classpath entry /dev/null for target a:a is located outside the working directory "{}".'.format(self.pants_workdir),
      str(cm.exception))
  def test_transitive_dependencies_excluded_classpath_element(self):
    b = self.make_target('b', JvmTarget, excludes=[Exclude('com.example', 'lib')])
    a = self.make_target('a', JvmTarget, dependencies=[b])

    classpath_product = ClasspathProducts(self.pants_workdir)
    self.add_jar_classpath_element_for_path(classpath_product, a, self._example_jar_path())
    self.add_excludes_for_targets(classpath_product, b, a)

    classpath = classpath_product.get_for_target(a)
    self.assertEqual([], classpath)
 def _bootstrap_classpath(self, jvm_tool, targets):
   self._check_underspecified_tools(jvm_tool, targets)
   workunit_name = 'bootstrap-{}'.format(jvm_tool.key)
   if JvmResolveSubsystem.global_instance().get_options().resolver == 'ivy':
     ivy_classpath = self.ivy_classpath(targets, silent=True, workunit_name=workunit_name)
     return ivy_classpath
   else:
     classpath_holder = ClasspathProducts(self.get_options().pants_workdir)
     CoursierMixin.resolve(self, targets, classpath_holder, sources=False, javadoc=False, executor=None)
     coursier_classpath = [cp_entry for _, cp_entry in classpath_holder.get_for_targets(targets)]
     return coursier_classpath
  def test_get_product_target_mappings_for_targets_respect_excludes(self):
    a = self.make_target('a', JvmTarget, excludes=[Exclude('com.example', 'lib')])

    classpath_product = ClasspathProducts(self.pants_workdir)
    example_jar_path = self._example_jar_path()
    self.add_jar_classpath_element_for_path(classpath_product, a, example_jar_path)
    self.add_excludes_for_targets(classpath_product, a)

    classpath_by_product = classpath_product.get_product_target_mappings_for_targets([a])

    self.assertEqual([], classpath_by_product)
示例#11
0
    def test_jar_missing_pants_path_fails_adding(self):
        b = self.make_target("b", JvmTarget)

        classpath_products = ClasspathProducts(self.pants_workdir)
        with self.assertRaises(TaskError) as cm:
            classpath_products.add_jars_for_targets(
                [b],
                "default",
                [ResolvedJar(M2Coordinate(org="org", name="name"), cache_path="somewhere", pants_path=None)],
            )
        self.assertEqual("Jar: org:name:::jar has no specified path.", str(cm.exception))
  def test_excludes_org_name(self):
    b = self.make_target('b', JvmTarget)
    a = self.make_target('a', JvmTarget, excludes=[Exclude('com.example')], dependencies=[b])

    classpath_product = ClasspathProducts(self.pants_workdir)
    self.add_example_jar_classpath_element_for(classpath_product, b)
    self.add_excludes_for_targets(classpath_product, a)

    classpath = classpath_product.get_for_target(a)

    self.assertEqual([], classpath)
示例#13
0
    def test_excluded_classpath_element(self):
        a = self.make_target("a", JvmTarget, excludes=[Exclude("com.example", "lib")])

        classpath_product = ClasspathProducts(self.pants_workdir)
        example_jar_path = self._example_jar_path()
        self.add_jar_classpath_element_for_path(classpath_product, a, example_jar_path)
        self.add_excludes_for_targets(classpath_product, a)

        classpath = classpath_product.get_for_target(a)

        self.assertEqual([], classpath)
  def test_excludes_used_across_targets(self):
    b = self.make_target('b', JvmTarget)
    a = self.make_target('a', JvmTarget, excludes=[Exclude('com.example', 'lib')])

    classpath_product = ClasspathProducts(self.pants_workdir)
    self.add_example_jar_classpath_element_for(classpath_product, b)
    self.add_excludes_for_targets(classpath_product, a)

    classpath = classpath_product.get_for_target(a)

    self.assertEqual([], classpath)
示例#15
0
  def test_excluded_classpath_element(self):
    a = self.make_target('a', JvmTarget, excludes=[Exclude('com.example', 'lib')])

    classpath_product = ClasspathProducts()
    example_jar_path = self._example_jar_path()
    self.add_jar_classpath_element_for_path(classpath_product, a, example_jar_path)
    self.add_excludes_for_targets(classpath_product, a)

    classpath = classpath_product.get_for_target(a)

    self.assertEqual([], classpath)
  def test_excludes_similar_org_name(self):
    b = self.make_target('b', JvmTarget)
    a = self.make_target('a', JvmTarget, excludes=[Exclude('com.exam')], dependencies=[b])

    classpath_product = ClasspathProducts(self.pants_workdir)
    self.add_example_jar_classpath_element_for(classpath_product, b)
    self.add_excludes_for_targets(classpath_product, a)

    classpath = classpath_product.get_for_targets(a.closure(bfs=True))

    self.assertEqual([('default', self._example_jar_path())], classpath)
  def test_parent_excludes_ignored_for_resolving_child_target(self):
    b = self.make_target('b', JvmTarget)
    a = self.make_target('a', JvmTarget, dependencies=[b], excludes=[Exclude('com.example', 'lib')])

    example_jar_path = self._example_jar_path()
    classpath_product = ClasspathProducts(self.pants_workdir)
    self.add_jar_classpath_element_for_path(classpath_product, b, example_jar_path)
    self.add_excludes_for_targets(classpath_product, a)

    classpath = classpath_product.get_for_target(b)

    self.assertEqual([('default', example_jar_path)], classpath)
示例#18
0
    def test_parent_exclude_excludes_dependency_jar(self):
        b = self.make_target("b", JvmTarget)
        a = self.make_target("a", JvmTarget, dependencies=[b], excludes=[Exclude("com.example", "lib")])

        classpath_product = ClasspathProducts(self.pants_workdir)
        example_jar_path = self._example_jar_path()
        self.add_jar_classpath_element_for_path(classpath_product, b, example_jar_path)
        self.add_excludes_for_targets(classpath_product, b, a)

        classpath = classpath_product.get_for_target(a)

        self.assertEqual([], classpath)
  def test_jar_provided_exclude_with_similar_org(self):
    provider = self.make_target('provider', ExportableJvmLibrary,
                         provides=Artifact('com.example.lib', '', Repository()))
    root = self.make_target('root', JvmTarget, dependencies=[provider])

    classpath_product = ClasspathProducts(self.pants_workdir)
    self.add_example_jar_classpath_element_for(classpath_product, root)
    self.add_excludes_for_targets(classpath_product, provider, root)

    classpath = classpath_product.get_for_target(root)

    self.assertEqual([('default', self._example_jar_path())], classpath)
示例#20
0
    def test_get_product_target_mappings_for_targets_ignore_excludes(self):
        a = self.make_target("a", JvmTarget, excludes=[Exclude("com.example", "lib")])

        classpath_product = ClasspathProducts(self.pants_workdir)
        example_jar_path = self._example_jar_path()
        resolved_jar = self.add_jar_classpath_element_for_path(classpath_product, a, example_jar_path, conf="fred-conf")
        self.add_excludes_for_targets(classpath_product, a)

        classpath_target_tuples = classpath_product.get_product_target_mappings_for_targets([a], respect_excludes=False)

        expected_entry = ArtifactClasspathEntry(example_jar_path, resolved_jar.coordinate, resolved_jar.cache_path)
        self.assertEqual([(("fred-conf", expected_entry), a)], classpath_target_tuples)
  def test_jar_missing_pants_path_fails_adding(self):
    b = self.make_target('b', JvmTarget)

    classpath_products = ClasspathProducts(self.pants_workdir)
    with self.assertRaises(TaskError) as cm:
      classpath_products.add_jars_for_targets([b], 'default',
                                              [ResolvedJar(M2Coordinate(org='org', name='name'),
                                                           cache_path='somewhere',
                                                           pants_path=None)])
    self.assertEqual(
      'Jar: org:name: has no specified path.',
      str(cm.exception))
示例#22
0
  def test_parent_exclude_excludes_dependency_jar(self):
    b = self.make_target('b', JvmTarget)
    a = self.make_target('a', JvmTarget, dependencies=[b], excludes=[Exclude('com.example', 'lib')])

    classpath_product = ClasspathProducts()
    example_jar_path = self._example_jar_path()
    self.add_jar_classpath_element_for_path(classpath_product, b, example_jar_path)
    self.add_excludes_for_targets(classpath_product, b, a)

    classpath = classpath_product.get_for_target(a)

    self.assertEqual([], classpath)
  def test_jar_provided_exclude_with_similar_name(self):
    # note exclude 'jars/com.example/l' should not match jars/com.example/lib/jars/123.4.jar
    provider = self.make_target('provider', ExportableJvmLibrary,
                         provides=Artifact('com.example', 'li', Repository()))
    root = self.make_target('root', JvmTarget, dependencies=[provider])

    classpath_product = ClasspathProducts(self.pants_workdir)
    self.add_example_jar_classpath_element_for(classpath_product, root)
    self.add_excludes_for_targets(classpath_product, provider, root)

    classpath = classpath_product.get_for_target(root)

    self.assertEqual([('default', self._example_jar_path())], classpath)
  def test_jar_provided_by_transitive_target_excluded(self):
    provider = self.make_target('provider', ExportableJvmLibrary,
                         provides=Artifact('com.example', 'lib', Repository()))
    consumer = self.make_target('consumer', JvmTarget)
    root = self.make_target('root', JvmTarget, dependencies=[provider, consumer])

    classpath_product = ClasspathProducts(self.pants_workdir)
    self.add_example_jar_classpath_element_for(classpath_product, consumer)
    self.add_excludes_for_targets(classpath_product, consumer, provider, root)

    classpath = classpath_product.get_for_target(root)

    self.assertEqual([], classpath)
  def test_jar_in_classpath_not_a_resolved_jar_ignored_by_excludes(self):
    b = self.make_target('b', JvmTarget)
    a = self.make_target('a', JvmTarget, excludes=[Exclude('com.example')], dependencies=[b])

    example_jar_path = self._example_jar_path()

    classpath_product = ClasspathProducts(self.pants_workdir)
    classpath_product.add_for_target(b, [('default', example_jar_path)])
    self.add_excludes_for_targets(classpath_product, a)

    classpath = classpath_product.get_for_targets(a.closure(bfs=True))

    self.assertEqual([('default', example_jar_path)], classpath)
 def execute(self):
   basedir = os.path.join(self.get_options().pants_distdir, self._output_folder)
   runtime_classpath = self.context.products.get_data('runtime_classpath')
   targets = self.context.targets()
   if self.get_options().manifest_jar_only:
     classpath = ClasspathUtil.classpath(targets, runtime_classpath)
     # Safely create e.g. dist/export-classpath/manifest.jar
     safe_classpath(classpath, basedir, "manifest.jar")
   else:
     ClasspathProducts.create_canonical_classpath(runtime_classpath,
                                                  targets,
                                                  basedir,
                                                  save_classpath_file=True)
示例#27
0
    def test_fails_if_paths_outside_buildroot(self):
        a = self.make_target("a", JvmTarget)

        classpath_product = ClasspathProducts(self.pants_workdir)
        with self.assertRaises(TaskError) as cm:
            classpath_product.add_for_target(a, [("default", "/dev/null")])

        self.assertEqual(
            'Classpath entry /dev/null for target a:a is located outside the working directory "{}".'.format(
                self.pants_workdir
            ),
            str(cm.exception),
        )
示例#28
0
    def test_get_classpath_entries_for_targets_dedup(self):
        b = self.make_target("b", JvmTarget)
        a = self.make_target("a", JvmTarget, dependencies=[b])
        classpath_product = ClasspathProducts(self.pants_workdir)
        example_jar_path = self._example_jar_path()

        # resolved_jar is added for both a and b but should return only as one classpath entry
        resolved_jar = self.add_jar_classpath_element_for_path(classpath_product, a, example_jar_path, conf="fred-conf")
        self.add_jar_classpath_element_for_path(classpath_product, b, example_jar_path, conf="fred-conf")
        classpath_target_tuples = classpath_product.get_classpath_entries_for_targets([a], respect_excludes=False)

        expected_entry = ArtifactClasspathEntry(example_jar_path, resolved_jar.coordinate, resolved_jar.cache_path)
        self.assertEqual([("fred-conf", expected_entry)], classpath_target_tuples)
示例#29
0
  def test_path_with_overlapped_conf_added(self):
    a = self.make_target('a', JvmTarget)

    classpath_product = ClasspathProducts(self.pants_workdir)

    path = os.path.join(self.pants_workdir, 'jar/path')
    classpath_product.add_for_target(a, [('default', path)])

    classpath = ClasspathUtil.compute_classpath([a],
                                                classpath_product,
                                                extra_classpath_tuples=[],
                                                confs=['not-default', 'default'])

    self.assertEqual([path], classpath)
示例#30
0
  def test_get_classpath_entries_for_targets_ignore_excludes(self):
    a = self.make_target('a', JvmTarget, excludes=[Exclude('com.example', 'lib')])

    classpath_product = ClasspathProducts()
    example_jar_path = self._example_jar_path()
    resolved_jar = self.add_jar_classpath_element_for_path(classpath_product, a, example_jar_path,
                                                           conf='fred-conf')
    self.add_excludes_for_targets(classpath_product, a)

    classpath = classpath_product.get_classpath_entries_for_targets([a], respect_excludes=False)

    expected_entry = ArtifactClasspathEntry(example_jar_path,
                                            resolved_jar.coordinate,
                                            resolved_jar.cache_path)
    self.assertEqual([('fred-conf', expected_entry)], list(classpath))
示例#31
0
    def test_create_canonical_classpath_no_duplicate_entry(self):
        """Test no more than one symlink are created for the same classpath entry."""
        jar_path = "ivy/jars/org.x/lib/x-1.0.jar"
        resolved_jar = ResolvedJar(
            M2Coordinate(org="org", name="x", rev="1.0"),
            cache_path="somewhere",
            pants_path=self._create_file(jar_path),
        )
        target_a = self.make_target("a", JvmTarget)
        target_b = self.make_target("b", JvmTarget)

        classpath_products = ClasspathProducts(self.pants_workdir)
        # Both target a and target b depend on the same jar library
        classpath_products.add_jars_for_targets([target_a], "default",
                                                [resolved_jar])
        classpath_products.add_jars_for_targets([target_b], "default",
                                                [resolved_jar])

        with temporary_dir() as base_dir:
            # Only target a generates symlink to jar library, target b skips creating the
            # symlink for the same jar library. Both targets' classpath.txt files should
            # still contain the jar library.
            self._test_canonical_classpath_helper(
                classpath_products,
                [target_a, target_b],
                base_dir,
                ["a.a-0.jar"],
                {
                    "a.a-classpath.txt": f"{self.pants_workdir}/{jar_path}\n",
                    "b.b-classpath.txt": f"{self.pants_workdir}/{jar_path}\n",
                },
            )
示例#32
0
    def test_create_canonical_classpath_with_common_prefix(self):
        """
    A special case when two targets' canonical classpath share a common prefix.

    Until we use `target.id` for canonical classpath, today's implementation is error-prone.
    This is such a regression test case added for a bug discovered in
    https://github.com/pantsbuild/pants/pull/2664

    NOTE: incremental test case is covered by `RuntimeClasspathPublisherTest`.
    TODO(peiyu) Remove once we fully migrate to use `target.id`.
    """
        # a and c' canonical classpath share a common prefix: a/b/b
        a = self.make_target('a/b', JvmTarget)
        c = self.make_target('a/b/b/c', JvmTarget)

        classpath_products = ClasspathProducts(self.pants_workdir)

        classpath_products.add_for_target(a,
                                          [('default', self._path('a.jar'))])
        classpath_products.add_for_target(c,
                                          [('default', self._path('c.jar'))])

        # target c first to verify its first created canonical classpath is preserved
        with temporary_dir() as base_dir:
            self._test_canonical_classpath_helper(
                classpath_products, [c, a], base_dir, False, [
                    'a/b/b/c/c/0.jar',
                    'a/b/b/0.jar',
                ], {
                    'a/b/b/classpath.txt':
                    '{}/a.jar\n'.format(self.pants_workdir),
                    'a/b/b/c/c/classpath.txt':
                    '{}/c.jar\n'.format(self.pants_workdir),
                })
    def test_create_canonical_classpath_no_duplicate_entry(self):
        """Test no more than one symlink are created for the same classpath entry."""
        jar_path = 'ivy/jars/org.x/lib/x-1.0.jar'
        resolved_jar = ResolvedJar(M2Coordinate(org='org', name='x',
                                                rev='1.0'),
                                   cache_path='somewhere',
                                   pants_path=self._create_file(jar_path))
        target_a = self.make_target('a', JvmTarget)
        target_b = self.make_target('b', JvmTarget)

        classpath_products = ClasspathProducts(self.pants_workdir)
        # Both target a and target b depend on the same jar library
        classpath_products.add_jars_for_targets([target_a], 'default',
                                                [resolved_jar])
        classpath_products.add_jars_for_targets([target_b], 'default',
                                                [resolved_jar])

        with temporary_dir() as base_dir:
            # Only target a generates symlink to jar library, target b skips creating the
            # symlink for the same jar library. Both targets' classpath.txt files should
            # still contain the jar library.
            self._test_canonical_classpath_helper(
                classpath_products, [target_a, target_b], base_dir,
                ['a.a-0.jar'], {
                    'a.a-classpath.txt':
                    '{}/{}\n'.format(self.pants_workdir, jar_path),
                    'b.b-classpath.txt':
                    '{}/{}\n'.format(self.pants_workdir, jar_path),
                })
示例#34
0
    def bundle(self, app, results_dir):
        """Create a self-contained application bundle.

        The bundle will contain the target classes, dependencies and resources.
        """
        assert isinstance(app, BundleCreate.App)

        bundle_dir = self.get_bundle_dir(app.id, results_dir)
        self.context.log.debug(
            f"creating {os.path.relpath(bundle_dir, get_buildroot())}")

        safe_mkdir(bundle_dir, clean=True)

        classpath = OrderedSet()

        # Create symlinks for both internal and external dependencies under `lib_dir`. This is
        # only needed when not creating a deployjar
        lib_dir = os.path.join(bundle_dir, self.LIBS_DIR)
        if not app.deployjar:
            os.mkdir(lib_dir)
            consolidated_classpath = self.context.products.get_data(
                "consolidated_classpath")
            classpath.update(
                ClasspathProducts.create_canonical_classpath(
                    consolidated_classpath,
                    app.target.closure(bfs=True,
                                       **self._target_closure_kwargs),
                    lib_dir,
                    internal_classpath_only=False,
                    excludes=app.binary.deploy_excludes,
                ))

        bundle_jar = os.path.join(bundle_dir, f"{app.binary.basename}.jar")
        with self.monolithic_jar(app.binary,
                                 bundle_jar,
                                 manifest_classpath=classpath) as jar:
            self.add_main_manifest_entry(jar, app.binary)

            # Make classpath complete by adding the monolithic jar.
            classpath.update([jar.path])

        if app.binary.shading_rules:
            for jar_path in classpath:
                # In case `jar_path` is a symlink, this is still safe, shaded jar will overwrite jar_path,
                # original file `jar_path` linked to remains untouched.
                # TODO run in parallel to speed up
                self.shade_jar(shading_rules=app.binary.shading_rules,
                               jar_path=jar_path)

        self.symlink_bundles(app, bundle_dir)

        return bundle_dir
示例#35
0
    def map_external_jars(self, targets):
        external_jar_dir = os.path.join(self.gen_project_workdir,
                                        'external-libs')
        safe_mkdir(external_jar_dir, clean=True)

        external_source_jar_dir = os.path.join(self.gen_project_workdir,
                                               'external-libsources')
        safe_mkdir(external_source_jar_dir, clean=True)

        external_javadoc_jar_dir = os.path.join(self.gen_project_workdir,
                                                'external-libjavadoc')
        safe_mkdir(external_javadoc_jar_dir, clean=True)

        classpath_products = self.resolve_jars(targets) or ClasspathProducts(
            self.get_options().pants_workdir)
        cp_entry_by_classifier_by_orgname = defaultdict(
            lambda: defaultdict(dict))
        for conf, jar_entry in classpath_products.get_artifact_classpath_entries_for_targets(
                targets):
            coord = (jar_entry.coordinate.org, jar_entry.coordinate.name)
            classifier = jar_entry.coordinate.classifier
            cp_entry_by_classifier_by_orgname[coord][classifier] = jar_entry

        def copy_jar(cp_entry, dest_dir):
            if not cp_entry:
                return None
            cp_jar = os.path.join(dest_dir, os.path.basename(cp_entry.path))
            shutil.copy(cp_entry.path, cp_jar)
            return cp_jar

        # Per org.name (aka maven "project"), collect the primary artifact and any extra classified
        # artifacts, taking special note of 'sources' and 'javadoc' artifacts that IDEs handle specially
        # to provide source browsing and javadocs for 3rdparty libs.
        for cp_entry_by_classifier in cp_entry_by_classifier_by_orgname.values(
        ):
            primary_jar = copy_jar(cp_entry_by_classifier.pop(None, None),
                                   external_jar_dir)
            sources_jar = copy_jar(cp_entry_by_classifier.pop('sources', None),
                                   external_source_jar_dir)
            javadoc_jar = copy_jar(cp_entry_by_classifier.pop('javadoc', None),
                                   external_javadoc_jar_dir)
            if primary_jar:
                self._project.external_jars.add(
                    ClasspathEntry(jar=primary_jar,
                                   source_jar=sources_jar,
                                   javadoc_jar=javadoc_jar))

            # Treat all other jars as opaque with no source or javadoc attachments of their own.  An
            # example are jars with the 'tests' classifier.
            for jar_entry in cp_entry_by_classifier.values():
                extra_jar = copy_jar(jar_entry, external_jar_dir)
                self._project.external_jars.add(ClasspathEntry(extra_jar))
示例#36
0
    def ensure_classpath_products(self, context):
        """Gets or creates the classpath products expected by `JvmBinaryTask`.

    :API: public

    :param context: The pants run context to get/create/associate classpath products with.
    :type context: :class:`pants.goal.context.Context`
    :returns: The classpath products associated with the given `context`
    :rtype: :class:`pants.backend.jvm.tasks.classpath_products.ClasspathProducts`
    """
        return context.products.get_data('runtime_classpath',
                                         init_func=ClasspathProducts.init_func(
                                             self.pants_workdir))
示例#37
0
 def resolve_jars(self, targets):
     executor = self.create_java_executor()
     confs = ['default']
     if self.get_options().source_jars:
         confs.append('sources')
     if self.get_options().javadoc_jars:
         confs.append('javadoc')
     compile_classpath = ClasspathProducts(self.get_options().pants_workdir)
     self.resolve(executor=executor,
                  targets=targets,
                  classpath_products=compile_classpath,
                  confs=confs)
     return compile_classpath
示例#38
0
  def test_intransitive_dependencies_excluded_classpath_element(self):
    b = self.make_target('b', JvmTarget, excludes=[Exclude('com.example', 'lib')])
    a = self.make_target('a', JvmTarget, dependencies=[b])

    classpath_product = ClasspathProducts(self.pants_workdir)
    example_jar_path = self._example_jar_path()
    classpath_product.add_for_target(a, [('default', example_jar_path)])
    classpath_product.add_excludes_for_targets([a, b])

    intransitive_classpath = classpath_product.get_for_target(a)
    self.assertEqual([('default', example_jar_path)], intransitive_classpath)
示例#39
0
    def _assert_jars_created(self, *, transitive_only: bool) -> None:
        with temporary_dir(
                root_dir=self.pants_workdir) as jar_dir, temporary_dir(
                    root_dir=self.pants_workdir) as dist_dir:
            self.set_options(pants_distdir=dist_dir,
                             transitive_only=transitive_only)

            init_target = self.make_target(
                "java/classpath:java_lib",
                target_type=JavaLibrary,
                sources=["com/foo/Bar.java"],
            )
            target_with_dep = self.make_target(
                "java/classpath:java_lib_with_dep",
                target_type=JavaLibrary,
                sources=["com/foo/Bar.java"],
                dependencies=[init_target],
            )
            context = self.context(target_roots=[target_with_dep])
            runtime_classpath = context.products.get_data(
                "runtime_classpath",
                init_func=ClasspathProducts.init_func(self.pants_workdir))
            task = self.create_task(context)

            target_classpath_output = os.path.join(dist_dir,
                                                   self.options_scope)

            # Create a classpath entry.
            touch(os.path.join(jar_dir, "dep-target.jar"))
            touch(os.path.join(jar_dir, "root-target.jar"))
            runtime_classpath.add_for_target(
                init_target,
                [(self.DEFAULT_CONF, os.path.join(jar_dir, "dep-target.jar"))])
            runtime_classpath.add_for_target(target_with_dep, [
                (self.DEFAULT_CONF, os.path.join(jar_dir, "root-target.jar"))
            ])
            task.execute()

            all_output = os.listdir(target_classpath_output)

            # Check only one symlink and classpath.txt were created.
            expected_artifacts = 2 if transitive_only else 4
            self.assertEqual(len(all_output), expected_artifacts)

            self.assertIn("java.classpath.java_lib-0.jar", all_output)
            if transitive_only:
                self.assertNotIn("java.classpath.java_lib_with_dep-0.jar",
                                 all_output)
            else:
                self.assertIn("java.classpath.java_lib_with_dep-0.jar",
                              all_output)
示例#40
0
    def execute(self):
        targets = self.context.targets(predicate=self.is_node_module)
        if not targets:
            return

        node_paths = self.context.products.get_data(NodePaths)
        # This is required even if node does not need `compile_classpaths` because certain downstream
        # tasks require `runtime_classpath` to be initialized correctly with `compile_classpaths`
        compile_classpath = self.context.products.get_data(
            'compile_classpath',
            init_func=ClasspathProducts.init_func(
                self.get_options().pants_workdir))
        runtime_classpath = self.context.products.get_data(
            'runtime_classpath', compile_classpath.copy)

        bundleable_js_product = self.context.products.get_data(
            'bundleable_js',
            init_func=lambda: defaultdict(MultipleRootedProducts))

        with self.invalidated(
                targets, invalidate_dependents=True) as invalidation_check:
            for vt in invalidation_check.all_vts:
                target = vt.target
                node_installed_path = node_paths.node_path(target)

                with pushd(node_installed_path):
                    if not vt.valid:
                        self._run_build_script(target, vt.results_dir,
                                               node_installed_path,
                                               node_paths.all_node_paths)
                    if not target.payload.dev_dependency:
                        output_dir = self._get_output_dir(
                            target, node_installed_path)
                        # Make sure that there is output generated.
                        if not os.path.exists(output_dir):
                            raise TaskError(
                                'Target {} has build script {} specified, but did not generate any output '
                                'at {}.\n'.format(target.address.reference(),
                                                  target.payload.build_script,
                                                  output_dir))
                        absolute_symlink(
                            output_dir,
                            os.path.join(vt.results_dir,
                                         target.address.target_name))
                        bundleable_js_product[target].add_abs_paths(
                            output_dir, [output_dir])

                        runtime_classpath.add_for_target(
                            target,
                            [('default',
                              self._snapshotted_classpath(vt.results_dir))])
示例#41
0
    def execute(self):
        deprecated_conditional(
            lambda: True,
            removal_version="1.30.0.dev0",
            entity_description="The `imports` goal",
            hint_message="Contact the Pants team on Slack or [email protected] "
            "if you need this functionality.",
        )
        jar_import_products = self.context.products.get_data(
            JarImportProducts, init_func=JarImportProducts
        )

        # Gather all targets that are both capable of importing jars and actually declare some imports.
        targets = self.context.targets(predicate=self.has_imports)
        if not targets:
            return

        # Create a list of all of these targets plus the list of JarDependencies they depend on.
        all_targets = set(targets)
        for target in targets:
            all_targets.update(target.imported_targets)

        imports_classpath = ClasspathProducts(self.get_options().pants_workdir)
        self.resolve(
            targets=all_targets,
            compile_classpath=imports_classpath,
            sources=False,
            javadoc=False,
            executor=self.create_java_executor(),
        )

        for target in targets:
            cp_entries = imports_classpath.get_classpath_entries_for_targets(
                target.closure(bfs=True)
            )
            for conf, cp_entry in cp_entries:
                if isinstance(cp_entry, ArtifactClasspathEntry):
                    jar_import_products.imported(target, cp_entry.coordinate, cp_entry.path)
示例#42
0
 def _bootstrap_classpath(self, jvm_tool, targets):
     self._check_underspecified_tools(jvm_tool, targets)
     workunit_name = 'bootstrap-{}'.format(jvm_tool.key)
     if JvmResolveSubsystem.global_instance().get_options(
     ).resolver == 'ivy':
         ivy_classpath = self.ivy_classpath(targets,
                                            silent=True,
                                            workunit_name=workunit_name)
         return ivy_classpath
     else:
         classpath_holder = ClasspathProducts(
             self.get_options().pants_workdir)
         CoursierMixin.resolve(self,
                               targets,
                               classpath_holder,
                               sources=False,
                               javadoc=False,
                               executor=None)
         coursier_classpath = [
             cp_entry
             for _, cp_entry in classpath_holder.get_for_targets(targets)
         ]
         return coursier_classpath
示例#43
0
    def test_exclude_leaves_other_jars_unaffected(self):
        b = self.make_target("b",
                             JvmTarget,
                             excludes=[Exclude("com.example", "lib")])
        a = self.make_target("a", JvmTarget, dependencies=[b])

        classpath_product = ClasspathProducts(self.pants_workdir)
        com_example_jar_path = self._example_jar_path()
        org_example_jar_path = self.path("ivy/jars/org.example/lib/123.4.jar")
        classpath_product.add_jars_for_targets(
            [a],
            "default",
            [
                resolved_example_jar_at(com_example_jar_path),
                resolved_example_jar_at(org_example_jar_path,
                                        org="org.example"),
            ],
        )
        self.add_excludes_for_targets(classpath_product, b)

        classpath = classpath_product.get_for_target(a)

        self.assertEqual([("default", org_example_jar_path)], classpath)
示例#44
0
    def test_excluded_classpath_element(self):
        a = self.make_target('a',
                             JvmTarget,
                             excludes=[Exclude('com.example', 'lib')])

        classpath_product = ClasspathProducts()
        example_jar_path = self._example_jar_path()
        classpath_product.add_for_target(a, [('default', example_jar_path)])
        classpath_product.add_excludes_for_targets([a])

        classpath = classpath_product.get_for_target(a)

        self.assertEqual([], classpath)
示例#45
0
    def test_copy(self):
        b = self.make_target("b",
                             JvmTarget,
                             excludes=[Exclude("com.example", "lib")])
        a = self.make_target("a", JvmTarget, dependencies=[b])

        classpath_product = ClasspathProducts(self.pants_workdir)
        resolved_jar = self.add_jar_classpath_element_for_path(
            classpath_product, a, self._example_jar_path())
        classpath_product.add_for_target(a, [("default", self.path("a/path"))])

        copied = classpath_product.copy()

        a_closure = a.closure(bfs=True)

        self.assertEqual(
            [("default", resolved_jar.pants_path),
             ("default", self.path("a/path"))],
            classpath_product.get_for_targets(a_closure),
        )
        self.assertEqual(
            [("default", resolved_jar.pants_path),
             ("default", self.path("a/path"))],
            copied.get_for_targets(a_closure),
        )

        self.add_excludes_for_targets(copied, b, a)
        self.assertEqual(
            [("default", resolved_jar.pants_path),
             ("default", self.path("a/path"))],
            classpath_product.get_for_targets(a_closure),
        )
        self.assertEqual([("default", self.path("a/path"))],
                         copied.get_for_targets(a_closure))

        copied.add_for_target(b, [("default", self.path("b/path"))])
        self.assertEqual(
            [("default", resolved_jar.pants_path),
             ("default", self.path("a/path"))],
            classpath_product.get_for_targets(a_closure),
        )
        self.assertEqual(
            [("default", self.path("a/path")),
             ("default", self.path("b/path"))],
            copied.get_for_targets(a_closure),
        )
示例#46
0
    def execute(self):
        cp_init_func = ClasspathProducts.init_func(
            self.get_options().pants_workdir)
        compile_classpath = self.context.products.get_data(
            'compile_classpath', init_func=cp_init_func)

        with self.invalidated(
                self.context.targets(is_tools_jar)) as invalidation_check:
            for vt in invalidation_check.all_vts:
                tools_classpath = self._tools_classpath_pairs(vt.results_dir)
                if not vt.valid:
                    self._symlink_tools_classpath(tools_classpath)
                compile_classpath.add_for_target(
                    vt.target,
                    [('default', entry) for _, entry in tools_classpath])
示例#47
0
  def execute(self):
    """Resolves the specified confs for the configured targets and returns an iterator over
    tuples of (conf, jar path).
    """

    jvm_resolve_subsystem = JvmResolveSubsystem.global_instance()
    if jvm_resolve_subsystem.get_options().resolver != 'coursier':
      return

    # executor = self.create_java_executor()
    classpath_products = self.context.products.get_data('compile_classpath',
                                                        init_func=ClasspathProducts.init_func(
                                                          self.get_options().pants_workdir))

    self.resolve(self.context.targets(), classpath_products, sources=False, javadoc=False)
  def _setup(self, target_classfiles):
    """Takes a dict mapping targets to lists of classfiles."""
    context = self.context(target_roots=target_classfiles.keys())

    # Create classfiles in a target-specific directory, and add it to the classpath for the target.
    classpath_products = context.products.get_data('runtime_classpath', ClasspathProducts.init_func(self.pants_workdir))
    for target, classfiles in target_classfiles.items():
      target_dir = os.path.join(self.test_workdir, target.id)
      safe_mkdir(target_dir)
      for classfile in classfiles:
        touch(os.path.join(target_dir, classfile))
      classpath_products.add_for_target(target, [('default', target_dir)])

    product_deps_by_src = context.products.get_data('product_deps_by_src', dict)
    return self.create_task(context), product_deps_by_src
示例#49
0
    def execute(self):
        """Resolves the specified confs for the configured targets and returns an iterator over
        tuples of (conf, jar path)."""

        classpath_products = self.context.products.get_data(
            "compile_classpath",
            init_func=ClasspathProducts.init_func(self.get_options().pants_workdir),
        )
        executor = self.create_java_executor()
        self.resolve(
            self.context.targets(),
            classpath_products,
            sources=self.context.products.is_required_data("resolve_sources_signal"),
            javadoc=self.context.products.is_required_data("resolve_javadocs_signal"),
            executor=executor,
        )
示例#50
0
    def test_excludes_used_across_targets(self):
        b = self.make_target('b', JvmTarget)
        a = self.make_target('a',
                             JvmTarget,
                             excludes=[Exclude('com.example', 'lib')])

        classpath_product = ClasspathProducts()
        classpath_product.add_for_target(
            b, [('default', self._example_jar_path())])
        classpath_product.add_excludes_for_targets([a])

        classpath = classpath_product.get_for_target(a)

        self.assertEqual([], classpath)
示例#51
0
    def test_excludes_org_name(self):
        b = self.make_target('b', JvmTarget)
        a = self.make_target('a',
                             JvmTarget,
                             excludes=[Exclude('com.example')],
                             dependencies=[b])

        classpath_product = ClasspathProducts()
        classpath_product.add_for_target(
            b, [('default', self._example_jar_path())])
        classpath_product.add_excludes_for_targets([a])

        classpath = classpath_product.get_for_target(a)

        self.assertEqual([], classpath)
示例#52
0
    def test_parent_exclude_excludes_dependency_jar(self):
        b = self.make_target('b', JvmTarget)
        a = self.make_target('a',
                             JvmTarget,
                             dependencies=[b],
                             excludes=[Exclude('com.example', 'lib')])

        classpath_product = ClasspathProducts()
        example_jar_path = self._example_jar_path()
        classpath_product.add_for_target(b, [('default', example_jar_path)])
        classpath_product.add_excludes_for_targets([a, b])

        classpath = classpath_product.get_for_target(a)

        self.assertEqual([], classpath)
示例#53
0
 def execute(self):
     """Resolves the specified confs for the configured targets and returns an iterator over
 tuples of (conf, jar path).
 """
     executor = self.create_java_executor()
     targets = self.context.targets()
     compile_classpath = self.context.products.get_data(
         'compile_classpath',
         init_func=ClasspathProducts.init_func(
             self.get_options().pants_workdir))
     resolve_hash_name = self.resolve(executor=executor,
                                      targets=targets,
                                      classpath_products=compile_classpath,
                                      confs=self.confs,
                                      extra_args=self._args)
     if self._report:
         self._generate_ivy_report(resolve_hash_name)
示例#54
0
    def test_jar_provided_exclude_with_similar_org(self):
        provider = self.make_target('provider',
                                    ExportableJvmLibrary,
                                    provides=Artifact('com.example.lib', '',
                                                      Repository()))
        root = self.make_target('root', JvmTarget, dependencies=[provider])

        classpath_product = ClasspathProducts()
        classpath_product.add_for_target(
            root, [('default', self._example_jar_path())])
        classpath_product.add_excludes_for_targets([root, provider])

        classpath = classpath_product.get_for_target(root)

        self.assertEqual([('default', self._example_jar_path())], classpath)
示例#55
0
 def resolve_jars(self, targets):
     """Resolve
 :param targets: targets that have dependencies to resolve
 :return: structure containing the path to resolved jars
 :rtype:  ClasspathProducts
 """
     executor = SubprocessExecutor(DistributionLocator.cached())
     classpath_products = self.context.products.get_data(
         'classpath_products',
         init_func=ClasspathProducts.init_func(
             self.get_options().pants_workdir))
     self.resolve(executor=executor,
                  targets=targets,
                  classpath_products=classpath_products,
                  confs=['default'],
                  extra_args=())
     return classpath_products
示例#56
0
    def test_jar_provided_exclude_with_similar_name(self):
        # note exclude 'jars/com.example/l' should not match jars/com.example/lib/jars/123.4.jar
        provider = self.make_target('provider',
                                    ExportableJvmLibrary,
                                    provides=Artifact('com.example', 'li',
                                                      Repository()))
        root = self.make_target('root', JvmTarget, dependencies=[provider])

        classpath_product = ClasspathProducts()
        classpath_product.add_for_target(
            root, [('default', self._example_jar_path())])
        classpath_product.add_excludes_for_targets([root, provider])

        classpath = classpath_product.get_for_target(root)

        self.assertEqual([('default', self._example_jar_path())], classpath)
示例#57
0
  def test_resolve_specific_with_sources_javadocs(self):
    # Create a jar_library with a single dep, and another library with no deps.
    dep = JarDependency('commons-lang', 'commons-lang', '2.5')
    jar_lib = self.make_target('//:a', JarLibrary, jars=[dep])
    scala_lib = self.make_target('//:b', JavaLibrary, sources=[])
    with self._temp_workdir() as workdir:
      # Confirm that the deps were added to the appropriate targets.
      context = self.context(target_roots=[jar_lib, scala_lib])
      task = self.prepare_execute(context)
      compile_classpath = context.products.get_data('compile_classpath',
        init_func=ClasspathProducts.init_func(workdir)
      )
      task.resolve([jar_lib, scala_lib], compile_classpath, sources=True, javadoc=True, executor=None)

      # Both javadoc and sources jars are added to the classpath product
      self.assertEqual(['default', 'src_doc', 'src_doc'],
       sorted([c[0] for c in compile_classpath.get_for_target(jar_lib)]))
      self.assertEqual(0, len(compile_classpath.get_for_target(scala_lib)))
示例#58
0
    def add_consolidated_bundle(self, context, tgt, files_dict):
        """Add a bundle to the classpath as if it has been consolidated already."""
        consolidated_classpath = context.products.get_data(
            "consolidated_classpath",
            init_func=ClasspathProducts.init_func(self.pants_workdir))
        # Create a temporary directory under the target id, then dump all files.
        target_dir = os.path.join(self.test_workdir, tgt.id)
        safe_mkdir(target_dir)
        entry_path = safe_mkdtemp(dir=target_dir)
        classpath_dir = safe_mkdtemp(dir=target_dir)
        for rel_path, content in files_dict.items():
            safe_file_dump(os.path.join(entry_path, rel_path), content)

        # Create Jar to mimic consolidate classpath behavior.
        jarpath = os.path.join(classpath_dir, "output-0.jar")
        with self.task.open_jar(jarpath, overwrite=True,
                                compressed=False) as jar:
            jar.write(entry_path)
        consolidated_classpath.add_for_target(tgt, [("default", jarpath)])
示例#59
0
    def test_target_annotation_processor(self):
        options = attrdict(coverage=True, coverage_jvm_options=[])

        syscalls = MockSystemCalls()
        settings = self.get_settings(options, syscalls)

        classpath_products = ClasspathProducts(self.pants_workdir)
        self._add_for_target(classpath_products, self.annotation_target,
                             "anno/target/dir")

        Cobertura.initialize_instrument_classpath(self.pants_workdir, settings,
                                                  [self.annotation_target],
                                                  classpath_products)

        self.assertEqual(len(syscalls.copy2_calls), 0,
                         "Should be 0 call for the single annotation target.")
        self._assert_target_copytree(syscalls,
                                     frm="anno/target/dir",
                                     to="coverage/classes/foo.foo-anno/0")
示例#60
0
    def _test_canonical_classpath_helper(
        self,
        classpath_products,
        targets,
        libs_dir,
        expected_canonical_classpath,
        expected_classpath_files,
        excludes=None,
    ):
        """Helper method to call `create_canonical_classpath` and verify generated canonical
        classpath.

        :param ClasspathProducts classpath_products: Classpath products.
        :param list targets: List of targets to generate canonical classpath from.
        :param string libs_dir: Directory where canonical classpath are to be generated.
        :param list expected_canonical_classpath: List of canonical classpath relative to a base directory.
        :param dict expected_classpath_files: A dict of classpath.txt path to its expected content.
        """
        canonical_classpath = ClasspathProducts.create_canonical_classpath(
            classpath_products,
            targets,
            libs_dir,
            save_classpath_file=True,
            internal_classpath_only=False,
            excludes=excludes,
        )
        # check canonical path returned
        self.assertEqual(expected_canonical_classpath,
                         relativize_paths(canonical_classpath, libs_dir))

        # check canonical path created contain the exact set of files, no more, no less
        self.assertTrue(
            contains_exact_files(
                libs_dir, expected_canonical_classpath +
                list(expected_classpath_files.keys())))

        # check the content of classpath.txt
        for classpath_file in expected_classpath_files:
            self.assertTrue(
                check_file_content(
                    os.path.join(libs_dir, classpath_file),
                    expected_classpath_files[classpath_file],
                ))