Пример #1
0
  def _check_bundle_products(self, bundle_name_prefix, check_symlink=False, symlink_name_prefix=''):
    products = self.task_context.products.get('jvm_bundles')
    bundle_fullname = '{}-bundle'.format(bundle_name_prefix)
    bundle_root = self._check_products(products, bundle_fullname)
    self.assertTrue(os.path.isdir(bundle_root))

    self.assertEqual(sorted(['foo-binary.jar',
                             'libs/foo.foo-binary-0.jar',
                             'libs/3rdparty.jvm.org.example.foo-0.jar',
                             'libs/3rdparty.jvm.org.example.foo-1.zip',
                             'libs/3rdparty.jvm.org.example.foo-2.jar',
                             'libs/3rdparty.jvm.org.example.foo-3.gz']),
                     sorted(self.iter_files(bundle_root)))

    with open_zip(os.path.join(bundle_root, 'libs/foo.foo-binary-0.jar')) as zf:
      self.assertEqual(sorted(['META-INF/',
                               'META-INF/MANIFEST.MF',
                               'Foo.class',
                               'foo.txt',
                               'foo/',
                               'foo/file']),
                       sorted(zf.namelist()))

    # TODO verify Manifest's Class-Path
    with open_zip(os.path.join(bundle_root, 'foo-binary.jar')) as jar:
      self.assertEqual(sorted(['META-INF/', 'META-INF/MANIFEST.MF']),
                       sorted(jar.namelist()))

    # Check symlink.
    if check_symlink:
      symlink_fullname = '{}-bundle'.format(symlink_name_prefix) if symlink_name_prefix else bundle_fullname
      symlink_path = os.path.join(self.dist_root, symlink_fullname)
      self.assertTrue(os.path.islink(symlink_path))
      self.assertEqual(os.readlink(symlink_path), bundle_root)
Пример #2
0
  def _check_bundle_products(self, bundle_basename):
    products = self.task_context.products.get('jvm_bundles')
    self.assertIsNotNone(products)
    product_data = products.get(self.app_target)
    self.assertEquals({self.dist_root: ['{basename}-bundle'.format(basename=bundle_basename)]},
                      product_data)

    self.assertTrue(os.path.exists(self.dist_root))
    bundle_root = os.path.join(self.dist_root,
                               '{basename}-bundle'.format(basename=bundle_basename))
    self.assertEqual(sorted(['foo-binary.jar',
                             'libs/foo.foo-binary-0.jar',
                             'libs/3rdparty.jvm.org.example.foo-0.jar',
                             'libs/3rdparty.jvm.org.example.foo-1.zip',
                             'libs/3rdparty.jvm.org.example.foo-2.jar',
                             'libs/3rdparty.jvm.org.example.foo-3.gz']),
                     sorted(self.iter_files(bundle_root)))

    with open_zip(os.path.join(bundle_root, 'libs/foo.foo-binary-0.jar')) as zf:
      self.assertEqual(sorted(['META-INF/',
                               'META-INF/MANIFEST.MF',
                               'Foo.class',
                               'foo.txt',
                               'foo/',
                               'foo/file']),
                       sorted(zf.namelist()))

    # TODO verify Manifest's Class-Path
    with open_zip(os.path.join(bundle_root, 'foo-binary.jar')) as jar:
      self.assertEqual(sorted(['META-INF/', 'META-INF/MANIFEST.MF']),
                       sorted(jar.namelist()))
Пример #3
0
    def _check_bundle_products(self, bundle_basename):
        products = self.task_context.products.get("jvm_bundles")
        self.assertIsNotNone(products)
        product_data = products.get(self.app_target)
        self.assertEquals({self.dist_root: ["{basename}-bundle".format(basename=bundle_basename)]}, product_data)

        self.assertTrue(os.path.exists(self.dist_root))
        bundle_root = os.path.join(self.dist_root, "{basename}-bundle".format(basename=bundle_basename))
        self.assertEqual(
            sorted(
                [
                    "foo-binary.jar",
                    "libs/foo.foo-binary-0.jar",
                    "libs/3rdparty.jvm.org.example.foo-0.jar",
                    "libs/3rdparty.jvm.org.example.foo-1.zip",
                    "libs/3rdparty.jvm.org.example.foo-2.jar",
                    "libs/3rdparty.jvm.org.example.foo-3.gz",
                ]
            ),
            sorted(self.iter_files(bundle_root)),
        )

        with open_zip(os.path.join(bundle_root, "libs/foo.foo-binary-0.jar")) as zf:
            self.assertEqual(
                sorted(["META-INF/", "META-INF/MANIFEST.MF", "Foo.class", "foo.txt", "foo/", "foo/file"]),
                sorted(zf.namelist()),
            )

        # TODO verify Manifest's Class-Path
        with open_zip(os.path.join(bundle_root, "foo-binary.jar")) as jar:
            self.assertEqual(sorted(["META-INF/", "META-INF/MANIFEST.MF"]), sorted(jar.namelist()))
Пример #4
0
  def test_jvm_binaries_products(self):
    binary_target = self.make_target(spec='//bar:bar-binary',
                                     target_type=JvmBinary,
                                     source='Bar.java')
    context = self.context(target_roots=[binary_target])
    classpath_products = self.ensure_classpath_products(context)

    jar_artifact = self.create_artifact(org='org.example', name='foo', rev='1.0.0')
    with open_zip(jar_artifact.pants_path, 'w') as jar:
      jar.writestr('foo/Foo.class', '')
    classpath_products.add_jars_for_targets(targets=[binary_target],
                                            conf='default',
                                            resolved_jars=[jar_artifact])

    with self.add_data(context.products, 'classes_by_target', binary_target, 'Bar.class'):
      with self.add_data(context.products, 'resources_by_target', binary_target, 'bar.txt'):
        self.execute(context)
        jvm_binary_products = context.products.get('jvm_binaries')
        self.assertIsNotNone(jvm_binary_products)
        product_data = jvm_binary_products.get(binary_target)
        dist_root = os.path.join(self.build_root, 'dist')
        self.assertEquals({dist_root: ['bar-binary.jar']}, product_data)

        with open_zip(os.path.join(dist_root, 'bar-binary.jar')) as jar:
          self.assertEqual(sorted(['META-INF/',
                                   'META-INF/MANIFEST.MF',
                                   'foo/',
                                   'foo/Foo.class',
                                   'Bar.class',
                                   'bar.txt']),
                           sorted(jar.namelist()))
Пример #5
0
  def test_jvm_binaries_products(self):
    self.add_to_build_file('bar', 'jvm_binary(name = "bar-binary", source = "Bar.java")')
    binary_target = self.target('//bar:bar-binary')
    context = self.context(target_roots=[binary_target])
    classpath_products = self.ensure_classpath_products(context)

    jar_artifact = self.create_artifact(org='org.example', name='foo', rev='1.0.0')
    with open_zip(jar_artifact.pants_path, 'w') as jar:
      jar.writestr('foo/Foo.class', '')
    classpath_products.add_jars_for_targets(targets=[binary_target],
                                            conf='default',
                                            resolved_jars=[jar_artifact])

    self.add_to_runtime_classpath(context, binary_target, {'Bar.class': '', 'bar.txt': ''})

    self.execute(context)

    jvm_binary_products = context.products.get('jvm_binaries')
    self.assertIsNotNone(jvm_binary_products)
    product_data = jvm_binary_products.get(binary_target)
    dist_root = os.path.join(self.build_root, 'dist')
    self.assertEquals({dist_root: ['bar-binary.jar']}, product_data)

    with open_zip(os.path.join(dist_root, 'bar-binary.jar')) as jar:
      self.assertEqual(sorted(['META-INF/',
                               'META-INF/MANIFEST.MF',
                               'foo/',
                               'foo/Foo.class',
                               'Bar.class',
                               'bar.txt']),
                       sorted(jar.namelist()))
Пример #6
0
 def test_open_zip_returns_realpath_on_badzipfile(self):
   # In case of file corruption, deleting a Pants-constructed symlink would not resolve the error.
   with temporary_file() as not_zip:
     with temporary_dir() as tempdir:
       file_symlink = os.path.join(tempdir, 'foo')
       os.symlink(not_zip.name, file_symlink)
       self.assertEquals(os.path.realpath(file_symlink), os.path.realpath(not_zip.name))
       with self.assertRaisesRegexp(zipfile.BadZipfile, r'{}'.format(not_zip.name)):
         open_zip(file_symlink).gen.next()
Пример #7
0
  def test_jvm_binaries_deploy_excludes(self):
    self.add_to_build_file(
      '3rdparty/jvm/org/example',
      'jar_library(name = "foo", jars = [jar(org = "org.example", name = "foo", rev = "1.0.0")])',
    )
    foo_jar_lib = self.target('3rdparty/jvm/org/example:foo')

    self.add_to_build_file(
      'bar',
      '''jvm_binary(
  name = "bar-binary",
  source = "Bar.java",
  dependencies = ["3rdparty/jvm/org/example:foo"],
  deploy_excludes = [exclude(org = "org.pantsbuild")],
)'''
    )
    binary_target = self.target('//bar:bar-binary')
    context = self.context(target_roots=[binary_target])
    classpath_products = self.ensure_classpath_products(context)


    foo_artifact = self.create_artifact(org='org.example', name='foo', rev='1.0.0')
    with open_zip(foo_artifact.pants_path, 'w') as jar:
      jar.writestr('foo/Foo.class', '')

    baz_artifact = self.create_artifact(org='org.pantsbuild', name='baz', rev='2.0.0')
    with open_zip(baz_artifact.pants_path, 'w') as jar:
      # This file should not be included in the binary jar since org.pantsbuild is deploy excluded.
      jar.writestr('baz/Baz.class', '')

    classpath_products.add_jars_for_targets(targets=[foo_jar_lib],
                                            conf='default',
                                            resolved_jars=[foo_artifact, baz_artifact])

    self.add_to_runtime_classpath(context, binary_target, {'Bar.class': '', 'bar.txt': ''})

    self.execute(context)
    jvm_binary_products = context.products.get('jvm_binaries')
    self.assertIsNotNone(jvm_binary_products)
    product_data = jvm_binary_products.get(binary_target)
    dist_root = os.path.join(self.build_root, 'dist')
    self.assertEquals({dist_root: ['bar-binary.jar']}, product_data)

    with open_zip(os.path.join(dist_root, 'bar-binary.jar')) as jar:
      self.assertEqual(sorted(['META-INF/',
                               'META-INF/MANIFEST.MF',
                               'foo/',
                               'foo/Foo.class',
                               'Bar.class',
                               'bar.txt']),
                       sorted(jar.namelist()))
Пример #8
0
def reversion(args):
  with temporary_dir() as workspace:
    # Extract the input.
    with open_zip(args.whl_file, 'r') as whl:
      src_filenames = whl.namelist()
      whl.extractall(workspace)

    # Determine the location of the `dist-info` directory.
    dist_info_dir = locate_dist_info_dir(workspace)
    record_file = os.path.join(dist_info_dir, 'RECORD')

    # Get version from the input whl's metadata.
    input_version = None
    metadata_file = os.path.join(workspace, dist_info_dir, 'METADATA')
    with open(metadata_file, 'r') as info:
      for line in info:
        mo = _version_re.match(line)
        if mo:
          input_version = mo.group('version')
          break
    if not input_version:
      raise Exception('Could not find `Version:` line in {}'.format(metadata_file))

    # Rewrite and move all files (including the RECORD file), recording which files need to be
    # re-fingerprinted due to content changes.
    dst_filenames = []
    refingerprint = []
    for src_filename in src_filenames:
      if os.path.isdir(os.path.join(workspace, src_filename)):
        continue
      dst_filename = src_filename
      if any_match(args.glob, src_filename):
        rewritten = replace_in_file(workspace, src_filename, input_version, args.target_version)
        if rewritten is not None:
          dst_filename = rewritten
          refingerprint.append((src_filename, dst_filename))
      dst_filenames.append(dst_filename)

    # Refingerprint relevant entries in the RECORD file under their new names.
    rewrite_record_file(workspace, record_file, refingerprint)

    # Create a new output whl in the destination.
    dst_whl_filename = os.path.basename(args.whl_file).replace(input_version, args.target_version)
    dst_whl_file = os.path.join(args.dest_dir, dst_whl_filename)
    with open_zip(dst_whl_file, 'w', zipfile.ZIP_DEFLATED) as whl:
      for dst_filename in dst_filenames:
        whl.write(os.path.join(workspace, dst_filename), dst_filename)

    print('Wrote whl with version {} to {}.\n'.format(args.target_version, dst_whl_file))
  def test_deploy_excludes(self):
    with temporary_dir() as distdir:
      def build(name):
        jar_filename = os.path.join(distdir, '{}.jar'.format(name))
        command = [
          '--pants-distdir={}'.format(distdir),
          '--no-compile-zinc-capture-classpath',
          'binary',
          'testprojects/src/java/org/pantsbuild/testproject/deployexcludes:{}'.format(name),
        ]
        self.assert_success(self.run_pants(command))
        return jar_filename

      # The excluded binary should not contain any guava classes, and should fail to run.
      jar_filename = build('deployexcludes')
      with open_zip(jar_filename) as jar_file:
        self.assertEqual({'META-INF/',
                           'META-INF/MANIFEST.MF',
                           'org/',
                           'org/pantsbuild/',
                           'org/pantsbuild/testproject/',
                           'org/pantsbuild/testproject/deployexcludes/',
                           'org/pantsbuild/testproject/deployexcludes/DeployExcludesMain.class'},
                          set(jar_file.namelist()))
      self.run_java(java_args=['-jar', jar_filename],
                    expected_returncode=1,
                    expected_output='java.lang.NoClassDefFoundError: '
                                    'com/google/common/collect/ImmutableSortedSet')

      # And the non excluded binary should succeed.
      jar_filename = build('nodeployexcludes')
      self.run_java(java_args=['-jar', jar_filename],
                    expected_output='DeployExcludes Hello World')
Пример #10
0
    def classpath_entries_contents(cls, classpath_entries):
        """Provide a generator over the contents (classes/resources) of a classpath.

    Subdirectories are included and differentiated via a trailing forward slash (for symmetry
    across ZipFile.namelist and directory walks).

    :param classpath_entries: A sequence of classpath_entries. Non-jars/dirs are ignored.
    :returns: An iterator over all classpath contents, one directory, class or resource relative
              path per iteration step.
    :rtype: :class:`collections.Iterator` of string
    """
        for entry in classpath_entries:
            if cls.is_jar(entry):
                # Walk the jar namelist.
                with open_zip(entry, mode="r") as jar:
                    for name in jar.namelist():
                        yield name
            elif os.path.isdir(entry):
                # Walk the directory, including subdirs.
                def rel_walk_name(abs_sub_dir, name):
                    return fast_relpath(os.path.join(abs_sub_dir, name), entry)

                for abs_sub_dir, dirnames, filenames in safe_walk(entry):
                    for name in dirnames:
                        yield "{}/".format(rel_walk_name(abs_sub_dir, name))
                    for name in filenames:
                        yield rel_walk_name(abs_sub_dir, name)
            else:
                # non-jar and non-directory classpath entries should be ignored
                pass
  def test_deploy_excludes(self):
    jar_filename = os.path.join('dist', 'deployexcludes.jar')
    safe_delete(jar_filename)
    command = [
      '--no-compile-zinc-capture-classpath',
      'binary',
      'testprojects/src/java/org/pantsbuild/testproject/deployexcludes',
    ]
    with self.pants_results(command) as pants_run:
      self.assert_success(pants_run)
      # The resulting binary should not contain any guava classes
      with open_zip(jar_filename) as jar_file:
        self.assertEquals({'META-INF/',
                           'META-INF/MANIFEST.MF',
                           'org/',
                           'org/pantsbuild/',
                           'org/pantsbuild/testproject/',
                           'org/pantsbuild/testproject/deployexcludes/',
                           'org/pantsbuild/testproject/deployexcludes/DeployExcludesMain.class'},
                          set(jar_file.namelist()))

      # This jar should not run by itself, missing symbols
      self.run_java(java_args=['-jar', jar_filename],
                    expected_returncode=1,
                    expected_output='java.lang.NoClassDefFoundError: '
                                    'com/google/common/collect/ImmutableSortedSet')

      # But adding back the deploy_excluded symbols should result in a clean run.
      classpath = [jar_filename,
                   os.path.join(pants_run.workdir,
                                'ivy/jars/com.google.guava/guava/jars/guava-18.0.jar')]

      self.run_java(java_args=['-cp', os.pathsep.join(classpath),
                               'org.pantsbuild.testproject.deployexcludes.DeployExcludesMain'],
                    expected_output='DeployExcludes Hello World')
 def assert_prep_compile(self):
   with temporary_dir() as tempdir:
     with open_zip('/tmp/running-in-goal-compile.jar') as jar:
       self.assertEquals(sorted(['BUILD',
                                 'ExampleJvmPrepCommand.java',
                                 'META-INF/', 'META-INF/MANIFEST.MF']),
                         sorted(jar.namelist()))
Пример #13
0
 def _iter_jar_packages(cls, path):
     with open_zip(path) as jar:
         paths = set()
         for pathname in jar.namelist():
             if cls._potential_package_path(pathname):
                 paths.add(os.path.dirname(pathname))
         return cls._iter_packages(paths)
Пример #14
0
 def generate_jar(path, *class_name):
   jar_path = os.path.join(self.test_workdir, 'jars', path)
   safe_mkdir_for(jar_path)
   with open_zip(jar_path, 'w') as zipfile:
     for clazz in class_name:
       zipfile.write(clazz, os.path.relpath(clazz, self.classes_dir))
     return jar_path
Пример #15
0
  def _compute_classpath_elements_by_class(self, classpath):
    """Computes a mapping of a .class file to its corresponding element on the given classpath."""
    # Don't consider loose classes dirs in our classes dir. Those will be considered
    # separately, by looking at products.
    def non_product(path):
      return path != self._classes_dir
    classpath_entries = filter(non_product, classpath)

    if self._upstream_class_to_path is None:
      self._upstream_class_to_path = {}
      for cp_entry in self._find_all_bootstrap_jars() + classpath_entries:
        # Per the classloading spec, a 'jar' in this context can also be a .zip file.
        if os.path.isfile(cp_entry) and (cp_entry.endswith('.jar') or cp_entry.endswith('.zip')):
          with open_zip(cp_entry, 'r') as jar:
            for cls in jar.namelist():
              # First jar with a given class wins, just like when classloading.
              if cls.endswith(b'.class') and not cls in self._upstream_class_to_path:
                self._upstream_class_to_path[cls] = cp_entry
        elif os.path.isdir(cp_entry):
          for dirpath, _, filenames in safe_walk(cp_entry, followlinks=True):
            for f in filter(lambda x: x.endswith('.class'), filenames):
              cls = os.path.relpath(os.path.join(dirpath, f), cp_entry)
              if not cls in self._upstream_class_to_path:
                self._upstream_class_to_path[cls] = os.path.join(dirpath, f)
    return self._upstream_class_to_path
 def test_scala_compile_jar(self):
   jar_suffix = 'z.jar'
   with self.do_test_compile(SHAPELESS_TARGET,
                             expected_files=[jar_suffix]) as found:
     with open_zip(self.get_only(found, jar_suffix), 'r') as jar:
       self.assertTrue(jar.getinfo(SHAPELESS_CLSFILE),
                       'Expected a jar containing the expected class.')
Пример #17
0
  def test_manifest_items(self):
    self.add_to_build_file('src/java/hello', dedent("""
        jvm_binary(
          name='hello',
          main='hello.Hello',
          manifest_entries = {
            'Foo': 'foo-value',
            'Implementation-Version': '1.2.3',
          },
        )""").strip())
    binary_target = self.target('src/java/hello:hello')
    context = self.context(target_roots=[binary_target])

    classfile = '.pants.d/javac/classes/hello/Hello.class'
    self.create_file(classfile, '0xDEADBEEF')
    self._add_to_classes_by_target(context, binary_target, classfile)
    context.products.safe_create_data('resources_by_target',
                                      lambda: defaultdict(MultipleRootedProducts))

    jar_task = self.prepare_jar_task(context)

    with self.jarfile() as existing_jarfile:
      with jar_task.open_jar(existing_jarfile) as jar:
        with jar_task.create_jar_builder(jar) as jar_builder:
          jar_builder.add_target(binary_target)

      with open_zip(existing_jarfile) as jar:
        manifest = jar.read('META-INF/MANIFEST.MF').strip()
        all_entries = dict(tuple(re.split(r'\s*:\s*', line, 1)) for line in manifest.splitlines())
        expected_entries = {
          'Foo': 'foo-value',
          'Implementation-Version': '1.2.3',
          }
        self.assertEquals(set(expected_entries.items()),
                          set(expected_entries.items()).intersection(set(all_entries.items())))
Пример #18
0
  def setUp(self):
    super(ClassmapTaskTest, self).setUp()
    init_subsystem(Target.Arguments)

    self.add_to_build_file(
      'a',
      'java_library(sources=["a1.java", "a2.java"])',
    )

    self.jar_artifact = self.create_artifact(org='org.example', name='foo', rev='1.0.0')
    with open_zip(self.jar_artifact.pants_path, 'w') as jar:
      jar.writestr('foo/Foo.class', '')

    self.add_to_build_file(
      'b',
      'jar_library(jars=[jar(org="org.example", name="foo", rev="1.0.0")])',
    )

    self.add_to_build_file(
      'c',
      'java_library(dependencies=["a", "b"])',
    )

    self.target_a = self.target('a')
    self.target_b = self.target('b')
    self.target_c = self.target('c')
Пример #19
0
def safe_classpath(classpath, synthetic_jar_dir):
  """Bundles classpath into one synthetic jar that includes original classpath in its manifest.

  This is to ensure classpath length never exceeds platform ARG_MAX.

  :param list classpath: Classpath to be bundled.
  :param string synthetic_jar_dir: directory to store the synthetic jar, if `None`
    a temp directory will be provided and cleaned up upon process exit. Otherwise synthetic
    jar will remain in the supplied directory, only for debugging purpose.

  :returns: A classpath (singleton list with just the synthetic jar).
  :rtype: list of strings
  """
  if synthetic_jar_dir:
    safe_mkdir(synthetic_jar_dir)
  else:
    synthetic_jar_dir = safe_mkdtemp()

  bundled_classpath = relativize_classpath(classpath, synthetic_jar_dir)

  manifest = Manifest()
  manifest.addentry(Manifest.CLASS_PATH, ' '.join(bundled_classpath))

  with temporary_file(root_dir=synthetic_jar_dir, cleanup=False, suffix='.jar') as jar_file:
    with open_zip(jar_file, mode='w', compression=ZIP_STORED) as jar:
      jar.writestr(Manifest.PATH, manifest.contents())
    return [jar_file.name]
Пример #20
0
def safe_classpath(classpath, synthetic_jar_dir, custom_name=None):
  """Bundles classpath into one synthetic jar that includes original classpath in its manifest.

  This is to ensure classpath length never exceeds platform ARG_MAX.

  :param list classpath: Classpath to be bundled.
  :param string synthetic_jar_dir: directory to store the synthetic jar, if `None`
    a temp directory will be provided and cleaned up upon process exit. Otherwise synthetic
    jar will remain in the supplied directory, only for debugging purpose.
  :param custom_name: filename of the synthetic jar to be created.

  :returns: A classpath (singleton list with just the synthetic jar).
  :rtype: list of strings
  """
  if synthetic_jar_dir:
    safe_mkdir(synthetic_jar_dir)
  else:
    synthetic_jar_dir = safe_mkdtemp()

  # Quote the paths so that if they contain reserved characters can be safely passed to JVM classloader.
  bundled_classpath = map(urllib.quote, relativize_classpath(classpath, synthetic_jar_dir))

  manifest = Manifest()
  manifest.addentry(Manifest.CLASS_PATH, ' '.join(bundled_classpath))

  with temporary_file(root_dir=synthetic_jar_dir, cleanup=False, suffix='.jar') as jar_file:
    with open_zip(jar_file, mode='w', compression=ZIP_STORED) as jar:
      jar.writestr(Manifest.PATH, manifest.contents())

    if custom_name:
      custom_path = os.path.join(synthetic_jar_dir, custom_name)
      safe_concurrent_rename(jar_file.name, custom_path)
      return [custom_path]
    else:
      return [jar_file.name]
Пример #21
0
  def test_manifest_items(self):
    self.add_to_build_file('src/java/hello', dedent("""
        jvm_binary(
          name='hello',
          main='hello.Hello',
          manifest_entries = {
            'Foo': 'foo-value',
            'Implementation-Version': '1.2.3',
          },
        )""").strip())
    binary_target = self.target('src/java/hello:hello')
    context = self.context(target_roots=[binary_target])

    self.add_to_runtime_classpath(context, binary_target, {'Hello.class': '0xDEADBEEF'})

    jar_builder_task = self.prepare_execute(context)

    with self.jarfile() as existing_jarfile:
      with jar_builder_task.open_jar(existing_jarfile) as jar:
        with jar_builder_task.create_jar_builder(jar) as jar_builder:
          jar_builder.add_target(binary_target)

      with open_zip(existing_jarfile) as jar:
        manifest = jar.read('META-INF/MANIFEST.MF').strip()
        all_entries = dict(tuple(re.split(r'\s*:\s*', line, 1)) for line in manifest.splitlines())
        expected_entries = {
          'Foo': 'foo-value',
          'Implementation-Version': '1.2.3',
          }
        self.assertEquals(set(expected_entries.items()),
                          set(expected_entries.items()).intersection(set(all_entries.items())))
Пример #22
0
 def sample_jarfile(self, name):
   with temporary_dir() as temp_dir:
     jar_name = os.path.join(temp_dir, '{}.jar'.format(name))
     with open_zip(jar_name, 'w') as proto_jarfile:
       proto_jarfile.writestr('a/b/c/{}.txt'.format(name), 'Some text')
       proto_jarfile.writestr('a/b/c/{}.proto'.format(name), 'message Msg {}')
     yield jar_name
Пример #23
0
def bundled_classpath(classpath):
  """Bundles classpath into one synthetic jar that includes original classpath in its manifest.

  See https://docs.oracle.com/javase/7/docs/technotes/guides/extensions/spec.html#bundled

  :param list classpath: Classpath to be bundled.

  :returns: A classpath (singleton list with just the synthetic jar).
  :rtype: list of strings
  """
  def prepare_url(url):
    url_in_bundle = os.path.realpath(url)
    # append '/' for directories, those not ending with '/' are assumed to be jars
    if os.path.isdir(url):
      url_in_bundle += '/'
    return url_in_bundle

  bundled_classpath = [prepare_url(url) for url in classpath]

  manifest = Manifest()
  manifest.addentry(Manifest.CLASS_PATH, ' '.join(bundled_classpath))

  with temporary_file(cleanup=False, suffix='.jar') as jar_file:
    with open_zip(jar_file, mode='w', compression=ZIP_STORED) as jar:
      jar.writestr(Manifest.PATH, manifest.contents())
    yield [jar_file.name]
Пример #24
0
  def _download_zip(self, zip_url, dest_dir):
    """Downloads a zip file at the given URL into the given directory.

    :param str zip_url: Full URL pointing to zip file.
    :param str dest_dir: Absolute path of directory into which the unzipped contents
                         will be placed into, not including the zip directory itself.
    """
    # TODO(jsirois): Wrap with workunits, progress meters, checksums.
    self.context.log.info('Downloading {}...'.format(zip_url))
    sess = requests.session()
    sess.mount('file://', self.LocalFileAdapter())
    res = sess.get(zip_url)
    if not res.status_code == requests.codes.ok:
      raise TaskError('Failed to download {} ({} error)'.format(zip_url, res.status_code))

    with open_zip(BytesIO(res.content)) as zfile:
      safe_mkdir(dest_dir)
      for info in zfile.infolist():
        if info.filename.endswith('/'):
          # Skip directories.
          continue
        # Strip zip directory name from files.
        filename = os.path.relpath(info.filename, get_basedir(info.filename))
        f = safe_open(os.path.join(dest_dir, filename), 'w')
        f.write(zfile.read(info))
        f.close()
Пример #25
0
  def test_bundled_classpath(self):
    """This creates the following classpath
      basedir/libs/A.jar:basedir/resources
    """
    RESOURCES = 'resources'
    LIB_DIR = 'libs'
    JAR_FILE = 'A.jar'

    basedir = safe_mkdtemp()
    lib_dir = os.path.join(basedir, LIB_DIR)
    resource_dir = os.path.join(lib_dir, RESOURCES)
    jar_file = os.path.join(lib_dir, JAR_FILE)

    for dir in (lib_dir, resource_dir):
      safe_mkdir(dir)
    touch(jar_file)

    classpath = [jar_file, resource_dir]

    with bundled_classpath(classpath) as bundled_cp:
      self.assertEquals(1, len(bundled_cp))
      bundled_jar = bundled_cp[0]
      self.assertTrue(os.path.exists(bundled_jar))

      with open_zip(bundled_jar) as synthetic_jar:
        self.assertListEqual([Manifest.PATH], synthetic_jar.namelist())
        # manifest should contain the absolute path of both jar and resource directory
        self.assertEquals('{}: {} {}/\n'.format(Manifest.CLASS_PATH, os.path.realpath(jar_file),
                                                os.path.realpath(resource_dir)),
                          synthetic_jar.read(Manifest.PATH).replace('\n ', ''))

    safe_rmtree(resource_dir)
Пример #26
0
  def _maybe_get_plugin_name(cls, classpath_element):
    """If classpath_element is a scalac plugin, returns its name.

    Returns None otherwise.
    """
    def process_info_file(cp_elem, info_file):
      plugin_info = ElementTree.parse(info_file).getroot()
      if plugin_info.tag != 'plugin':
        raise TaskError('File {} in {} is not a valid scalac plugin descriptor'.format(
            _SCALAC_PLUGIN_INFO_FILE, cp_elem))
      return plugin_info.find('name').text

    if os.path.isdir(classpath_element):
      try:
        with open(os.path.join(classpath_element, _SCALAC_PLUGIN_INFO_FILE)) as plugin_info_file:
          return process_info_file(classpath_element, plugin_info_file)
      except IOError as e:
        if e.errno != errno.ENOENT:
          raise
    else:
      with open_zip(classpath_element, 'r') as jarfile:
        try:
          with closing(jarfile.open(_SCALAC_PLUGIN_INFO_FILE, 'r')) as plugin_info_file:
            return process_info_file(classpath_element, plugin_info_file)
        except KeyError:
          pass
    return None
 def test_scala_compile_jar(self):
     # NB: generated with:
     #   hashlib.sha1('testprojects.src.scala.org.pantsbuild.testproject.unicode.shapeless.shapeless').hexdigest()[:12]
     jar_suffix = "fd9f49e1153b.jar"
     with self.do_test_compile(SHAPELESS_TARGET, expected_files=[jar_suffix]) as found:
         with open_zip(self.get_only(found, jar_suffix), "r") as jar:
             self.assertTrue(jar.getinfo(SHAPELESS_CLSFILE), "Expected a jar containing the expected class.")
Пример #28
0
  def _find_plugins(self):
    """Returns a map from plugin name to plugin jar."""
    # Allow multiple flags and also comma-separated values in a single flag.
    plugin_names = set([p for val in self.get_options().scalac_plugins for p in val.split(',')])
    plugins = {}
    buildroot = get_buildroot()
    for jar in self.plugin_jars:
      with open_zip(jar, 'r') as jarfile:
        try:
          with closing(jarfile.open(_PLUGIN_INFO_FILE, 'r')) as plugin_info_file:
            plugin_info = ElementTree.parse(plugin_info_file).getroot()
          if plugin_info.tag != 'plugin':
            raise TaskError(
              'File {} in {} is not a valid scalac plugin descriptor'.format(_PLUGIN_INFO_FILE,
                                                                             jar))
          name = plugin_info.find('name').text
          if name in plugin_names:
            if name in plugins:
              raise TaskError('Plugin {} defined in {} and in {}'.format(name, plugins[name], jar))
            # It's important to use relative paths, as the compiler flags get embedded in the zinc
            # analysis file, and we port those between systems via the artifact cache.
            plugins[name] = os.path.relpath(jar, buildroot)
        except KeyError:
          pass

    unresolved_plugins = plugin_names - set(plugins.keys())
    if unresolved_plugins:
      raise TaskError('Could not find requested plugins: {}'.format(list(unresolved_plugins)))
    return plugins
Пример #29
0
 def populate_input_jar(self, *entries):
   fd, input_jar_path = tempfile.mkstemp()
   os.close(fd)
   self.addCleanup(safe_delete, input_jar_path)
   with open_zip(input_jar_path, 'w') as jar:
     for entry in entries:
       jar.writestr(entry, '0xCAFEBABE')
   return input_jar_path
Пример #30
0
 def sample_jarfile(self):
   """Create a jar file with a/b/c/data.txt and a/b/c/foo.proto"""
   with temporary_dir() as temp_dir:
     jar_name = os.path.join(temp_dir, 'foo.jar')
     with open_zip(jar_name, 'w') as proto_jarfile:
       proto_jarfile.writestr('a/b/c/data.txt', 'Foo text')
       proto_jarfile.writestr('a/b/c/foo.proto', 'message Foo {}')
     yield jar_name
Пример #31
0
  def test_overwrite_jars(self):
    with self.jarfile() as main_jar:
      with self.jarfile() as included_jar:
        with self.jar_task.open_jar(main_jar) as jar:
          jar.writestr('a/b', b'c')

        with self.jar_task.open_jar(included_jar) as jar:
          jar.writestr('e/f', b'g')

        # Create lots of included jars (even though they're all the same)
        # so the -jars argument to jar-tool will exceed max_args limit thus
        # switch to @argfile calling style.
        with self.jar_task.open_jar(main_jar, overwrite=True) as jar:
          for i in range(self.MAX_SUBPROC_ARGS + 1):
            jar.writejar(included_jar)

        with open_zip(main_jar) as jar:
          self.assert_listing(jar, 'e/', 'e/f')
Пример #32
0
 def create(self, basedir, outdir, name, prefix=None):
     """
 :API: public
 """
     zippath = os.path.join(outdir, '{}.{}'.format(name, self.extension))
     with open_zip(zippath, 'w', compression=self.compression) as zip:
         # For symlinks, we want to archive the actual content of linked files but
         # under the relpath derived from symlink.
         for root, _, files in safe_walk(basedir, followlinks=True):
             root = ensure_text(root)
             for file in files:
                 file = ensure_text(file)
                 full_path = os.path.join(root, file)
                 relpath = os.path.relpath(full_path, basedir)
                 if prefix:
                     relpath = os.path.join(ensure_text(prefix), relpath)
                 zip.write(full_path, relpath)
     return zippath
Пример #33
0
  def assert_jar_contents(self, context, product_type, target, *contents):
    """Contents is a list of lists representing contents from particular classpath entries.

    Ordering across classpath entries is guaranteed, but not within classpath entries.
    """
    jar_mapping = context.products.get(product_type).get(target)
    self.assertEqual(1, len(jar_mapping))
    for basedir, jars in jar_mapping.items():
      self.assertEqual(1, len(jars))
      with open_zip(os.path.join(basedir, jars[0])) as jar:
        actual_iter = iter(jar.namelist())
        self.assertPrefixEqual(['META-INF/', 'META-INF/MANIFEST.MF'], actual_iter)
        for content_set in list(contents):
          self.assertUnorderedPrefixEqual(content_set, actual_iter)
          for content in content_set:
            if not content.endswith('/'):
              with closing(jar.open(content)) as fp:
                self.assertEqual(os.path.basename(content), fp.read())
Пример #34
0
    def extract(cls, path, outdir, filter_func=None):
        """Extract from a zip file, with an optional filter

    :API: public

    :param string path: path to the zipfile to extract from
    :param string outdir: directory to extract files into
    :param function filter_func: optional filter with the filename as the parameter.  Returns True if
      the file should be extracted.
    """
        with open_zip(path) as archive_file:
            for name in archive_file.namelist():
                # While we're at it, we also perform this safety test.
                if name.startswith(b'/') or name.startswith(b'..'):
                    raise ValueError(
                        'Zip file contains unsafe path: {}'.format(name))
                if (not filter_func or filter_func(name)):
                    archive_file.extract(name, outdir)
Пример #35
0
    def test_safe_classpath(self):
        """For directory structure like:

       ./
       ./libs/A.jar
       ./libs/resources/
       ./synthetic_jar_dir

       Verify a synthetic jar with the following classpath in manifest is created:

        Class-Path: ../libs/A.jar:../libs/resources/
    """
        RESOURCES = 'resources'
        LIB_DIR = 'libs'
        JAR_FILE = 'A.jar'
        SYNTHENTIC_JAR_DIR = 'synthetic_jar_dir'

        basedir = safe_mkdtemp()
        lib_dir = os.path.join(basedir, LIB_DIR)
        synthetic_jar_dir = os.path.join(basedir, SYNTHENTIC_JAR_DIR)
        resource_dir = os.path.join(lib_dir, RESOURCES)
        jar_file = os.path.join(lib_dir, JAR_FILE)

        for dir in (lib_dir, resource_dir, synthetic_jar_dir):
            safe_mkdir(dir)
        touch(jar_file)

        classpath = [jar_file, resource_dir]

        safe_cp = safe_classpath(classpath, synthetic_jar_dir)
        self.assertEqual(1, len(safe_cp))
        safe_jar = safe_cp[0]
        self.assertTrue(os.path.exists(safe_jar))
        self.assertEqual(synthetic_jar_dir, os.path.dirname(safe_jar))

        with open_zip(safe_jar) as synthetic_jar:
            self.assertEqual([Manifest.PATH], synthetic_jar.namelist())
            # manifest should contain the relative path of both jar and resource directory
            expected = ('{}: ../{}/{} ../{}/{}/\n'.format(
                Manifest.CLASS_PATH, LIB_DIR, JAR_FILE, LIB_DIR,
                RESOURCES).encode('utf-8'))
            self.assertEqual(
                expected,
                synthetic_jar.read(Manifest.PATH).replace(b'\n ', b''))
Пример #36
0
    def test_agent_manifest(self):
        self.add_to_build_file(
            'src/java/pants/agents',
            dedent("""
        java_agent(
          name='fake_agent',
          premain='bob',
          agent_class='fred',
          can_redefine=True,
          can_retransform=True,
          can_set_native_method_prefix=True
        )""").strip())
        java_agent = self.target('src/java/pants/agents:fake_agent')

        context = self.context(target_roots=[java_agent])
        jar_builder_task = self.prepare_execute(context)

        self.add_to_runtime_classpath(context, java_agent,
                                      {'FakeAgent.class': '0xCAFEBABE'})
        with self.jarfile() as existing_jarfile:
            with jar_builder_task.open_jar(existing_jarfile) as jar:
                with jar_builder_task.create_jar_builder(jar) as jar_builder:
                    jar_builder.add_target(java_agent)

            with open_zip(existing_jarfile) as jar:
                self.assert_listing(jar, 'FakeAgent.class')
                self.assertEqual(b'0xCAFEBABE', jar.read('FakeAgent.class'))

                manifest = jar.read('META-INF/MANIFEST.MF').decode(
                    'utf-8').strip()
                all_entries = dict(
                    tuple(re.split(r'\s*:\s*', line, 1))
                    for line in manifest.splitlines())
                expected_entries = {
                    'Agent-Class': 'fred',
                    'Premain-Class': 'bob',
                    'Can-Redefine-Classes': 'true',
                    'Can-Retransform-Classes': 'true',
                    'Can-Set-Native-Method-Prefix': 'true',
                }
                self.assertEqual(
                    set(expected_entries.items()),
                    set(expected_entries.items()).intersection(
                        set(all_entries.items())))
Пример #37
0
  def test_compile_wire_roots(self):
    pants_run = self.run_pants(['bundle.jvm', '--deployjar',
                                'examples/src/java/org/pantsbuild/example/wire/roots'])
    self.assert_success(pants_run)
    out_path = os.path.join(get_buildroot(), 'dist', 'wire-roots-example.jar')
    with open_zip(out_path) as zipfile:
      jar_entries = zipfile.namelist()

    def is_relevant(entry):
      return (entry.startswith('org/pantsbuild/example/roots/') and entry.endswith('.class')
              and '$' not in entry)

    expected_classes = {
      'org/pantsbuild/example/roots/Bar.class',
      'org/pantsbuild/example/roots/Foobar.class',
      'org/pantsbuild/example/roots/Fooboo.class',
    }
    received_classes = {entry for entry in jar_entries if is_relevant(entry)}
    self.assertEqual(expected_classes, received_classes)
Пример #38
0
        def assert_classpath(classpath):
            with self.jarfile() as existing_jarfile:
                # Note for -classpath, there is no update, it's already overwriting.
                # To verify this, first add a random classpath, and verify it's overwritten by
                # the supplied classpath value.
                with self.jar_task.open_jar(existing_jarfile) as jar:
                    # prefix with workdir since Class-Path is relative to jarfile.path
                    jar.append_classpath(
                        os.path.join(self.workdir,
                                     "something_should_be_overwritten.jar"))

                with self.jar_task.open_jar(existing_jarfile) as jar:
                    jar.append_classpath([
                        os.path.join(self.workdir, jar_path)
                        for jar_path in classpath
                    ])

                with open_zip(existing_jarfile) as jar:
                    self.assertEqual(manifest_content(classpath),
                                     jar.read("META-INF/MANIFEST.MF"))
Пример #39
0
  def extract(cls, path, outdir, filter_func=None):
    """Extract from a zip file, with an optional filter

    :param string path: path to the zipfile to extract from
    :param string outdir: directory to extract files into
    :param function filter_func: optional filter with the filename as the parameter.  Returns True if
      the file should be extracted.
    """
    with open_zip(path) as archive_file:
      for name in archive_file.namelist():
        # While we're at it, we also perform this safety test.
        if name.startswith(b'/') or name.startswith(b'..'):
          raise ValueError('Zip file contains unsafe path: {}'.format(name))
        # Ignore directories. extract() will create parent dirs as needed.
        # OS X's python 2.6.1 has a bug in zipfile that makes it unzip directories as regular files.
        # This method should work on for python 2.6-3.x.
        # TODO(Eric Ayers) Pants no longer builds with python 2.6. Can this be removed?
        if not name.endswith(b'/'):
          if (not filter_func or filter_func(name)):
            archive_file.extract(name, outdir)
Пример #40
0
      def publish(resource_content):
        with temporary_dir() as publish_dir:
          with self.temporary_file_content(resource, resource_content):
            # Validate that the target depends on the relevant resource.
            self.assertIn(resource, self.run_pants(['filedeps', target]).stdout_data)

            pants_run = self.run_pants_with_workdir(['publish.jar',
                                                     '--local={}'.format(publish_dir),
                                                     '--named-snapshot=X',
                                                     '--no-dryrun',
                                                     target
                                                    ],
                                                    workdir=workdir)
            self.assert_success(pants_run)
          # Validate that the content in the resulting jar matches.
          jar = os.path.join(publish_dir,
                             'org/pantsbuild/testproject/publish/hello-greet/X/hello-greet-X.jar')
          with open_zip(jar, mode='r') as j:
            with j.open(resource_relative_to_sourceroot) as jar_entry:
              self.assertEqual(resource_content, jar_entry.read())
Пример #41
0
 def test_agent_dependency(self):
     directory = "testprojects/src/java/org/pantsbuild/testproject/manifest"
     target = "{}:manifest-with-agent".format(directory)
     with self.temporary_workdir() as workdir:
         pants_run = self.run_pants_with_workdir(["binary", target],
                                                 workdir=workdir)
         self.assert_success(pants_run)
         jar = "dist/manifest-with-agent.jar"
         with open_zip(jar, mode='r') as j:
             with j.open("META-INF/MANIFEST.MF") as jar_entry:
                 normalized_lines = (line.decode('utf-8').strip()
                                     for line in jar_entry.readlines()
                                     if line.strip())
                 entries = {
                     tuple(line.split(": ", 2))
                     for line in normalized_lines
                 }
                 self.assertIn(
                     ('Agent-Class',
                      'org.pantsbuild.testproject.manifest.Agent'), entries)
Пример #42
0
    def test_deploy_excludes(self):
        with temporary_dir() as distdir:

            def build(name):
                jar_filename = os.path.join(distdir, f"{name}.jar")
                command = [
                    f"--pants-distdir={distdir}",
                    "--no-compile-rsc-capture-classpath",
                    "binary",
                    f"testprojects/src/java/org/pantsbuild/testproject/deployexcludes:{name}",
                ]
                self.assert_success(self.run_pants(command))
                return jar_filename

            # The excluded binary should not contain any guava classes, and should fail to run.
            jar_filename = build("deployexcludes")
            with open_zip(jar_filename) as jar_file:
                self.assertEqual(
                    {
                        "META-INF/",
                        "META-INF/MANIFEST.MF",
                        "org/",
                        "org/pantsbuild/",
                        "org/pantsbuild/testproject/",
                        "org/pantsbuild/testproject/deployexcludes/",
                        "org/pantsbuild/testproject/deployexcludes/DeployExcludesMain.class",
                    },
                    set(jar_file.namelist()),
                )
            self.run_java(
                java_args=["-jar", jar_filename],
                expected_returncode=1,
                expected_output="java.lang.NoClassDefFoundError: "
                "com/google/common/collect/ImmutableSortedSet",
            )

            # And the non excluded binary should succeed.
            jar_filename = build("nodeployexcludes")
            self.run_java(
                java_args=["-jar", jar_filename], expected_output="DeployExcludes Hello World"
            )
Пример #43
0
    def test_manifest_items(self):
        self.add_to_build_file(
            'src/java/hello',
            dedent("""
        jvm_binary(
          name='hello',
          main='hello.Hello',
          manifest_entries = {
            'Foo': 'foo-value',
            'Implementation-Version': '1.2.3',
          },
        )""").strip())
        binary_target = self.target('src/java/hello:hello')
        context = self.context(target_roots=[binary_target])

        classfile = '.pants.d/javac/classes/hello/Hello.class'
        self.create_file(classfile, '0xDEADBEEF')
        self._add_to_classes_by_target(context, binary_target, classfile)
        context.products.safe_create_data(
            'resources_by_target', lambda: defaultdict(MultipleRootedProducts))

        jar_task = self.prepare_jar_task(context)

        with self.jarfile() as existing_jarfile:
            with jar_task.open_jar(existing_jarfile) as jar:
                with jar_task.create_jar_builder(jar) as jar_builder:
                    jar_builder.add_target(binary_target)

            with open_zip(existing_jarfile) as jar:
                manifest = jar.read('META-INF/MANIFEST.MF').strip()
                all_entries = dict(
                    tuple(re.split(r'\s*:\s*', line, 1))
                    for line in manifest.splitlines())
                expected_entries = {
                    'Foo': 'foo-value',
                    'Implementation-Version': '1.2.3',
                }
                self.assertEquals(
                    set(expected_entries.items()),
                    set(expected_entries.items()).intersection(
                        set(all_entries.items())))
Пример #44
0
    def test_deploy_excludes(self):
        jar_filename = os.path.join('dist', 'deployexcludes.jar')
        safe_delete(jar_filename)
        command = [
            '--no-compile-zinc-capture-classpath',
            'binary',
            'testprojects/src/java/org/pantsbuild/testproject/deployexcludes',
        ]
        with self.pants_results(command) as pants_run:
            self.assert_success(pants_run)
            # The resulting binary should not contain any guava classes
            with open_zip(jar_filename) as jar_file:
                self.assertEquals(
                    {
                        'META-INF/', 'META-INF/MANIFEST.MF', 'org/',
                        'org/pantsbuild/', 'org/pantsbuild/testproject/',
                        'org/pantsbuild/testproject/deployexcludes/',
                        'org/pantsbuild/testproject/deployexcludes/DeployExcludesMain.class'
                    }, set(jar_file.namelist()))

            # This jar should not run by itself, missing symbols
            self.run_java(java_args=['-jar', jar_filename],
                          expected_returncode=1,
                          expected_output='java.lang.NoClassDefFoundError: '
                          'com/google/common/collect/ImmutableSortedSet')

            # But adding back the deploy_excluded symbols should result in a clean run.
            classpath = [
                jar_filename,
                os.path.join(
                    pants_run.workdir,
                    'ivy/jars/com.google.guava/guava/jars/guava-18.0.jar')
            ]

            self.run_java(java_args=[
                '-cp',
                os.pathsep.join(classpath),
                'org.pantsbuild.testproject.deployexcludes.DeployExcludesMain'
            ],
                          expected_output='DeployExcludes Hello World')
Пример #45
0
def safe_classpath(classpath, synthetic_jar_dir, custom_name=None):
    """Bundles classpath into one synthetic jar that includes original classpath in its manifest.

  This is to ensure classpath length never exceeds platform ARG_MAX.

  :param list classpath: Classpath to be bundled.
  :param string synthetic_jar_dir: directory to store the synthetic jar, if `None`
    a temp directory will be provided and cleaned up upon process exit. Otherwise synthetic
    jar will remain in the supplied directory, only for debugging purpose.
  :param custom_name: filename of the synthetic jar to be created.

  :returns: A classpath (singleton list with just the synthetic jar).
  :rtype: list of strings
  """
    if synthetic_jar_dir:
        safe_mkdir(synthetic_jar_dir)
    else:
        synthetic_jar_dir = safe_mkdtemp()

    # Quote the paths so that if they contain reserved characters can be safely passed to JVM classloader.
    bundled_classpath = [
        parse.quote(cp)
        for cp in relativize_classpath(classpath, synthetic_jar_dir)
    ]

    manifest = Manifest()
    manifest.addentry(Manifest.CLASS_PATH, ' '.join(bundled_classpath))

    with temporary_file(root_dir=synthetic_jar_dir,
                        cleanup=False,
                        suffix='.jar') as jar_file:
        with open_zip(jar_file, mode='w', compression=ZIP_STORED) as jar:
            jar.writestr(Manifest.PATH, manifest.contents())

        if custom_name:
            custom_path = os.path.join(synthetic_jar_dir, custom_name)
            safe_concurrent_rename(jar_file.name, custom_path)
            return [custom_path]
        else:
            return [jar_file.name]
Пример #46
0
    def test_manifest_items(self):
        self.add_to_build_file(
            "src/java/hello",
            dedent("""
                jvm_binary(
                  name='hello',
                  main='hello.Hello',
                  manifest_entries = {
                    'Foo': 'foo-value',
                    'Implementation-Version': '1.2.3',
                  },
                )""").strip(),
        )
        binary_target = self.target("src/java/hello:hello")
        context = self.context(target_roots=[binary_target])

        self.add_to_runtime_classpath(context, binary_target,
                                      {"Hello.class": "0xDEADBEEF"})

        jar_builder_task = self.prepare_execute(context)

        with self.jarfile() as existing_jarfile:
            with jar_builder_task.open_jar(existing_jarfile) as jar:
                with jar_builder_task.create_jar_builder(jar) as jar_builder:
                    jar_builder.add_target(binary_target)

            with open_zip(existing_jarfile) as jar:
                manifest = jar.read("META-INF/MANIFEST.MF").decode().strip()
                all_entries = dict(
                    tuple(re.split(r"\s*:\s*", line, 1))
                    for line in manifest.splitlines())
                expected_entries = {
                    "Foo": "foo-value",
                    "Implementation-Version": "1.2.3",
                }
                self.assertEqual(
                    set(expected_entries.items()),
                    set(expected_entries.items()).intersection(
                        set(all_entries.items())),
                )
Пример #47
0
    def test_ipex_gets_imprecise_constraint(self) -> None:
        cur_interpreter_id = PythonInterpreter.get().identity
        interpreter_name = cur_interpreter_id.requirement.name
        major, minor, patch = cur_interpreter_id.version

        # Pin the selected interpreter to the one used by pants to execute this test.
        cur_interpreter_constraint = f"{interpreter_name}=={major}.{minor}.{patch}"

        # Validate the the .ipex file specifically matches the major and minor versions, but allows
        # any patch version.
        imprecise_constraint = f"{interpreter_name}=={major}.{minor}.*"

        with temporary_dir() as tmp_dir:
            self.do_command(
                "--binary-py-generate-ipex",
                "binary",
                self.binary_target_address,
                config={
                    "GLOBAL": {
                        "pants_distdir": tmp_dir
                    },
                    "python-setup": {
                        "interpreter_constraints":
                        [cur_interpreter_constraint]
                    },
                },
            )

            pex_path = os.path.join(tmp_dir, "test.ipex")
            assert os.path.isfile(pex_path)
            pex_execution_result = subprocess.run([pex_path],
                                                  stdout=subprocess.PIPE,
                                                  check=True)
            assert pex_execution_result.stdout.decode() == "test!\n"

            with open_zip(pex_path) as zf:
                info = json.loads(zf.read("PEX-INFO"))
                constraint = assert_single_element(
                    info["interpreter_constraints"])
                assert constraint == imprecise_constraint
Пример #48
0
 def _get_external_dependencies(self, binary_target):
     artifacts_by_file_name = defaultdict(set)
     for basedir, externaljar in self.list_external_jar_dependencies(
             binary_target):
         external_dep = os.path.join(basedir, externaljar)
         self.context.log.debug('  scanning {}'.format(external_dep))
         with open_zip(external_dep) as dep_zip:
             for qualified_file_name in dep_zip.namelist():
                 # Zip entry names can come in any encoding and in practice we find some jars that have
                 # utf-8 encoded entry names, some not.  As a result we cannot simply decode in all cases
                 # and need to do this to_bytes(...).decode('utf-8') dance to stay safe across all entry
                 # name flavors and under all supported pythons.
                 decoded_file_name = to_bytes(qualified_file_name).decode(
                     'utf-8')
                 if os.path.basename(
                         decoded_file_name).lower() in self._excludes:
                     continue
                 jar_name = os.path.basename(external_dep)
                 if (not self._isdir(decoded_file_name)
                     ) and Manifest.PATH != decoded_file_name:
                     artifacts_by_file_name[decoded_file_name].add(jar_name)
     return artifacts_by_file_name
Пример #49
0
    def setUp(self):
        super(ClassmapTaskTest, self).setUp()
        init_subsystem(Target.Arguments)

        self.target_a = self.make_target('a',
                                         target_type=JavaLibrary,
                                         sources=['a1.java', 'a2.java'])

        self.jar_artifact = self.create_artifact(org='org.example',
                                                 name='foo',
                                                 rev='1.0.0')
        with open_zip(self.jar_artifact.pants_path, 'w') as jar:
            jar.writestr('foo/Foo.class', '')
        self.target_b = self.make_target(
            'b',
            target_type=JarLibrary,
            jars=[JarDependency(org='org.example', name='foo', rev='1.0.0')])

        self.target_c = self.make_target(
            'c',
            dependencies=[self.target_a, self.target_b],
            target_type=JavaLibrary)
Пример #50
0
    def test_compile_wire_roots(self):
        pants_run = self.run_pants(
            ["binary.jvm", "examples/src/java/org/pantsbuild/example/wire/roots"]
        )
        self.assert_success(pants_run)
        out_path = os.path.join(get_buildroot(), "dist", "wire-roots-example.jar")
        with open_zip(out_path) as zipfile:
            jar_entries = zipfile.namelist()

        def is_relevant(entry):
            return (
                entry.startswith("org/pantsbuild/example/roots/")
                and entry.endswith(".class")
                and "$" not in entry
            )

        expected_classes = {
            "org/pantsbuild/example/roots/Bar.class",
            "org/pantsbuild/example/roots/Foobar.class",
            "org/pantsbuild/example/roots/Fooboo.class",
        }
        received_classes = {entry for entry in jar_entries if is_relevant(entry)}
        self.assertEqual(expected_classes, received_classes)
Пример #51
0
    def _find_plugins(self):
        """Returns a map from plugin name to plugin jar."""
        # Allow multiple flags and also comma-separated values in a single flag.
        plugin_names = set([
            p for val in self.get_options().scalac_plugins
            for p in val.split(',')
        ])
        plugins = {}
        buildroot = get_buildroot()
        for jar in self.plugin_jars:
            with open_zip(jar, 'r') as jarfile:
                try:
                    with closing(jarfile.open(_PLUGIN_INFO_FILE,
                                              'r')) as plugin_info_file:
                        plugin_info = ElementTree.parse(
                            plugin_info_file).getroot()
                    if plugin_info.tag != 'plugin':
                        raise TaskError(
                            'File {} in {} is not a valid scalac plugin descriptor'
                            .format(_PLUGIN_INFO_FILE, jar))
                    name = plugin_info.find('name').text
                    if name in plugin_names:
                        if name in plugins:
                            raise TaskError(
                                'Plugin {} defined in {} and in {}'.format(
                                    name, plugins[name], jar))
                        # It's important to use relative paths, as the compiler flags get embedded in the zinc
                        # analysis file, and we port those between systems via the artifact cache.
                        plugins[name] = os.path.relpath(jar, buildroot)
                except KeyError:
                    pass

        unresolved_plugins = plugin_names - set(plugins.keys())
        if unresolved_plugins:
            raise TaskError('Could not find requested plugins: {}'.format(
                list(unresolved_plugins)))
        return plugins
Пример #52
0
def safe_classpath(classpath, synthetic_jar_dir):
  """Bundles classpath into one synthetic jar that includes original classpath in its manifest.

  This is to ensure classpath length never exceeds platform ARG_MAX. Original classpath are
  converted to URLs relative to synthetic jar path and saved in its manifest as attribute
  `Class-Path`. See
  https://docs.oracle.com/javase/7/docs/technotes/guides/extensions/spec.html#bundled

  :param list classpath: Classpath to be bundled.
  :param string synthetic_jar_dir: directory to store the synthetic jar, if `None`
    a temp directory will be provided and cleaned up upon process exit. Otherwise synthetic
    jar will remain in the supplied directory, only for debugging purpose.

  :returns: A classpath (singleton list with just the synthetic jar).
  :rtype: list of strings
  """
  def prepare_url(url, root_dir):
    url_in_bundle = os.path.relpath(os.path.realpath(url), os.path.realpath(root_dir))
    # append '/' for directories, those not ending with '/' are assumed to be jars
    if os.path.isdir(url):
      url_in_bundle += '/'
    return url_in_bundle

  if synthetic_jar_dir:
    safe_mkdir(synthetic_jar_dir)
  else:
    synthetic_jar_dir = safe_mkdtemp()
  bundled_classpath = [prepare_url(url, synthetic_jar_dir) for url in classpath]

  manifest = Manifest()
  manifest.addentry(Manifest.CLASS_PATH, ' '.join(bundled_classpath))

  with temporary_file(root_dir=synthetic_jar_dir, cleanup=False, suffix='.jar') as jar_file:
    with open_zip(jar_file, mode='w', compression=ZIP_STORED) as jar:
      jar.writestr(Manifest.PATH, manifest.contents())
    return [jar_file.name]
Пример #53
0
  def _check_bundle_products(self, bundle_basename):
    products = self.task_context.products.get('jvm_bundles')
    self.assertIsNotNone(products)
    product_data = products.get(self.app_target)
    self.assertEquals({self.dist_root: ['{basename}-bundle'.format(basename=bundle_basename)]},
                      product_data)

    self.assertTrue(os.path.exists(self.dist_root))
    bundle_root = os.path.join(self.dist_root,
                               '{basename}-bundle'.format(basename=bundle_basename))
    self.assertEqual(sorted(['foo-binary.jar',
                             'libs/foo.foo-binary-0.jar',
                             'libs/3rdparty.jvm.org.example.foo-0.jar',
                             'libs/3rdparty.jvm.org.example.foo-1.zip',
                             'libs/3rdparty.jvm.org.example.foo-2.jar',
                             'libs/3rdparty.jvm.org.example.foo-3.gz']),
                     sorted(self.iter_files(bundle_root)))
    check_zip_file_content(os.path.join(bundle_root, 'libs/foo.foo-binary-0.jar'),
                           self.FOO_JAR)

    # TODO verify Manifest's Class-Path
    with open_zip(os.path.join(bundle_root, 'foo-binary.jar')) as jar:
      self.assertEqual(sorted(['META-INF/', 'META-INF/MANIFEST.MF']),
                       sorted(jar.namelist()))
Пример #54
0
  def _compute_classpath_elements_by_class(self, classpath):
    # Don't consider loose classes dirs in our classes dir. Those will be considered
    # separately, by looking at products.
    def non_product(path):
      return path != self._classes_dir

    if self._upstream_class_to_path is None:
      self._upstream_class_to_path = {}
      classpath_entries = filter(non_product, classpath)
      for cp_entry in self._find_all_bootstrap_jars() + classpath_entries:
        # Per the classloading spec, a 'jar' in this context can also be a .zip file.
        if os.path.isfile(cp_entry) and (cp_entry.endswith('.jar') or cp_entry.endswith('.zip')):
          with open_zip(cp_entry, 'r') as jar:
            for cls in jar.namelist():
              # First jar with a given class wins, just like when classloading.
              if cls.endswith(b'.class') and not cls in self._upstream_class_to_path:
                self._upstream_class_to_path[cls] = cp_entry
        elif os.path.isdir(cp_entry):
          for dirpath, _, filenames in safe_walk(cp_entry, followlinks=True):
            for f in filter(lambda x: x.endswith('.class'), filenames):
              cls = os.path.relpath(os.path.join(dirpath, f), cp_entry)
              if not cls in self._upstream_class_to_path:
                self._upstream_class_to_path[cls] = os.path.join(dirpath, f)
    return self._upstream_class_to_path
Пример #55
0
    def setUp(self):
        super().setUp()
        init_subsystem(Target.Arguments)

        self.create_files("a", files=["a1.java", "a2.java"])
        self.add_to_build_file(
            "a", 'java_library(sources=["a1.java", "a2.java"])',
        )

        self.jar_artifact = self.create_artifact(org="org.example", name="foo", rev="1.0.0")
        with open_zip(self.jar_artifact.pants_path, "w") as jar:
            jar.writestr("foo/Foo.class", "")

        self.add_to_build_file(
            "b", 'jar_library(jars=[jar(org="org.example", name="foo", rev="1.0.0")])',
        )

        self.add_to_build_file(
            "c", 'java_library(dependencies=["a", "b"], sources=[])',
        )

        self.target_a = self.target("a")
        self.target_b = self.target("b")
        self.target_c = self.target("c")
Пример #56
0
 def _jar_classfiles(self, jar_file):
     """Returns an iterator over the classfiles inside jar_file."""
     with open_zip(jar_file, 'r') as jar:
         for cls in jar.namelist():
             if cls.endswith(b'.class'):
                 yield cls
Пример #57
0
 def test_open_zipFalse(self):
     with temporary_dir() as tempdir:
         with open_zip(os.path.join(tempdir, 'test'), 'w',
                       allowZip64=False) as zf:
             self.assertFalse(zf._allowZip64)
Пример #58
0
 def test_open_zip_raises_exception_on_falsey_paths(self):
     falsey = (None, '', False)
     for invalid in falsey:
         with self.assertRaises(InvalidZipPath):
             open_zip(invalid).gen.next()
Пример #59
0
    def test_jvm_binaries_deploy_excludes(self):
        self.add_to_build_file(
            "3rdparty/jvm/org/example",
            'jar_library(name = "foo", jars = [jar(org = "org.example", name = "foo", rev = "1.0.0")])',
        )
        foo_jar_lib = self.target("3rdparty/jvm/org/example:foo")

        self.create_file("bar/Bar.java")
        self.add_to_build_file(
            "bar",
            """jvm_binary(
              name = "bar-binary",
              sources = ["Bar.java"],
              dependencies = ["3rdparty/jvm/org/example:foo"],
              deploy_excludes = [exclude(org = "org.pantsbuild")],
            )""",
        )
        binary_target = self.target("//bar:bar-binary")
        context = self.context(target_roots=[binary_target])
        classpath_products = self.ensure_classpath_products(context)

        foo_artifact = self.create_artifact(org="org.example",
                                            name="foo",
                                            rev="1.0.0")
        with open_zip(foo_artifact.pants_path, "w") as jar:
            jar.writestr("foo/Foo.class", "")

        baz_artifact = self.create_artifact(org="org.pantsbuild",
                                            name="baz",
                                            rev="2.0.0")
        with open_zip(baz_artifact.pants_path, "w") as jar:
            # This file should not be included in the binary jar since org.pantsbuild is deploy excluded.
            jar.writestr("baz/Baz.class", "")

        classpath_products.add_jars_for_targets(
            targets=[foo_jar_lib],
            conf="default",
            resolved_jars=[foo_artifact, baz_artifact])

        self.add_to_runtime_classpath(context, binary_target, {
            "Bar.class": "",
            "bar.txt": ""
        })

        self.execute(context)
        jvm_binary_products = context.products.get("jvm_binaries")
        self.assertIsNotNone(jvm_binary_products)
        product_data = jvm_binary_products.get(binary_target)
        dist_root = os.path.join(self.build_root, "dist")
        self.assertEqual({dist_root: ["bar-binary.jar"]}, product_data)

        with open_zip(os.path.join(dist_root, "bar-binary.jar")) as jar:
            self.assertEqual(
                sorted([
                    "META-INF/",
                    "META-INF/MANIFEST.MF",
                    "foo/",
                    "foo/Foo.class",
                    "Bar.class",
                    "bar.txt",
                ]),
                sorted(jar.namelist()),
            )
Пример #60
0
 def open_jar(self, mode):
     with open_zip(self.jar_file, mode=mode,
                   compression=zipfile.ZIP_STORED) as jar:
         yield jar