diff options
author | Benjamin Gilbert <bgilbert@backtick.net> | 2022-12-13 21:12:41 -0500 |
---|---|---|
committer | Benjamin Gilbert <bgilbert@backtick.net> | 2022-12-14 15:37:59 -0500 |
commit | 35e230e48ca42f4ccb872d1d01f9280f8015b417 (patch) | |
tree | a55a759f1f3a37e6a8d2b1f3ebd4268fc0df57c6 | |
parent | 51c889ddbc8e83a73ef4d1f2556609bae2a046ce (diff) | |
download | meson-35e230e48ca42f4ccb872d1d01f9280f8015b417.tar.gz |
depfixer: silence fix_jar() and make it do something
fix_jar() tries to remove an existing Class-Path entry from the jar
manifest by postprocessing the manifest and passing it to `jar -um`.
However, `jar -um` can only add/replace manifest entries, not remove
them, and it also complains loudly when replacing an entry:
Dec 13, 2022 7:11:19 PM java.util.jar.Attributes read
WARNING: Duplicate name in Manifest: Manifest-Version.
Ensure that the manifest does not have duplicate entries, and
that blank lines separate individual sections in both your
manifest and in the META-INF/MANIFEST.MF entry in the jar file.
Thus fix_jar() produces one such warning for each entry in the manifest
and accomplishes nothing else.
Use jar -uM instead. This completely removes the manifest from the jar
and allows adding it back as a normal zip member, fixing fix_jar() and
avoiding the warnings.
Fixes: https://github.com/mesonbuild/meson/issues/10491
Fixes: c70a051e93 ("java: remove manifest classpath from installed jar")
-rw-r--r-- | mesonbuild/scripts/depfixer.py | 7 | ||||
-rw-r--r-- | test cases/unit/110 classpath/com/mesonbuild/Simple.java | 7 | ||||
-rw-r--r-- | test cases/unit/110 classpath/meson.build | 14 | ||||
-rw-r--r-- | unittests/helpers.py | 17 | ||||
-rw-r--r-- | unittests/machinefiletests.py | 18 |
5 files changed, 62 insertions, 1 deletions
diff --git a/mesonbuild/scripts/depfixer.py b/mesonbuild/scripts/depfixer.py index 702afeb80..8d9c90fe3 100644 --- a/mesonbuild/scripts/depfixer.py +++ b/mesonbuild/scripts/depfixer.py @@ -465,7 +465,12 @@ def fix_jar(fname: str) -> None: if not line.startswith('Class-Path:'): f.write(line) f.truncate() - subprocess.check_call(['jar', 'ufm', fname, 'META-INF/MANIFEST.MF']) + # jar -um doesn't allow removing existing attributes. Use -uM instead, + # which a) removes the existing manifest from the jar and b) disables + # special-casing for the manifest file, so we can re-add it as a normal + # archive member. This puts the manifest at the end of the jar rather + # than the beginning, but the spec doesn't forbid that. + subprocess.check_call(['jar', 'ufM', fname, 'META-INF/MANIFEST.MF']) def fix_rpath(fname: str, rpath_dirs_to_remove: T.Set[bytes], new_rpath: T.Union[str, bytes], final_path: str, install_name_mappings: T.Dict[str, str], verbose: bool = True) -> None: global INSTALL_NAME_TOOL # pylint: disable=global-statement diff --git a/test cases/unit/110 classpath/com/mesonbuild/Simple.java b/test cases/unit/110 classpath/com/mesonbuild/Simple.java new file mode 100644 index 000000000..325a49a21 --- /dev/null +++ b/test cases/unit/110 classpath/com/mesonbuild/Simple.java @@ -0,0 +1,7 @@ +package com.mesonbuild; + +class Simple { + public static void main(String [] args) { + System.out.println("Java is working.\n"); + } +} diff --git a/test cases/unit/110 classpath/meson.build b/test cases/unit/110 classpath/meson.build new file mode 100644 index 000000000..e6b9b840a --- /dev/null +++ b/test cases/unit/110 classpath/meson.build @@ -0,0 +1,14 @@ +project('simplejava', 'java') + +one = jar('one', 'com/mesonbuild/Simple.java', + main_class : 'com.mesonbuild.Simple', + install : true, + install_dir : get_option('bindir'), +) + +two = jar('two', 'com/mesonbuild/Simple.java', + main_class : 'com.mesonbuild.Simple', + install : true, + install_dir : get_option('bindir'), + link_with : one, +) diff --git a/unittests/helpers.py b/unittests/helpers.py index ac9d98073..d3d156056 100644 --- a/unittests/helpers.py +++ b/unittests/helpers.py @@ -5,6 +5,7 @@ import unittest import functools import re import typing as T +import zipfile from pathlib import Path from contextlib import contextmanager @@ -176,6 +177,22 @@ def get_rpath(fname: str) -> T.Optional[str]: return None return final +def get_classpath(fname: str) -> T.Optional[str]: + with zipfile.ZipFile(fname) as zip: + with zip.open('META-INF/MANIFEST.MF') as member: + contents = member.read().decode().strip() + lines = [] + for line in contents.splitlines(): + if line.startswith(' '): + # continuation line + lines[-1] += line[1:] + else: + lines.append(line) + manifest = { + k.lower(): v.strip() for k, v in [l.split(':', 1) for l in lines] + } + return manifest.get('class-path') + def get_path_without_cmd(cmd: str, path: str) -> str: pathsep = os.pathsep paths = OrderedSet([Path(p).resolve() for p in path.split(pathsep)]) diff --git a/unittests/machinefiletests.py b/unittests/machinefiletests.py index 7d75ebc34..bf109b247 100644 --- a/unittests/machinefiletests.py +++ b/unittests/machinefiletests.py @@ -42,6 +42,7 @@ import mesonbuild.modules.pkgconfig from run_tests import ( + Backend, get_fake_env ) @@ -368,6 +369,23 @@ class NativeFileTests(BasePlatformTests): self._single_implementation_compiler( 'java', 'javac', 'javac 9.99.77', '9.99.77') + @skip_if_not_language('java') + def test_java_classpath(self): + if self.backend is not Backend.ninja: + raise SkipTest('Jar is only supported with Ninja') + testdir = os.path.join(self.unit_test_dir, '110 classpath') + self.init(testdir) + self.build() + one_build_path = get_classpath(os.path.join(self.builddir, 'one.jar')) + self.assertIsNone(one_build_path) + two_build_path = get_classpath(os.path.join(self.builddir, 'two.jar')) + self.assertEqual(two_build_path, 'one.jar') + self.install() + one_install_path = get_classpath(os.path.join(self.installdir, 'usr/bin/one.jar')) + self.assertIsNone(one_install_path) + two_install_path = get_classpath(os.path.join(self.installdir, 'usr/bin/two.jar')) + self.assertIsNone(two_install_path) + @skip_if_not_language('swift') def test_swift_compiler(self): wrapper = self.helper_create_binary_wrapper( |