diff --git a/craft_parts/plugins/jlink_plugin.py b/craft_parts/plugins/jlink_plugin.py index 593847337..7d18e343d 100644 --- a/craft_parts/plugins/jlink_plugin.py +++ b/craft_parts/plugins/jlink_plugin.py @@ -125,18 +125,21 @@ def get_build_commands(self) -> list[str]: commands.append("CPATH=.") commands.append( """ - find ${CRAFT_PART_BUILD}/tmp -type f -name *.jar | while IFS= read -r file; do - CPATH=$CPATH:${file} + for file in $(find "${CRAFT_PART_BUILD}/tmp" -type f -name "*.jar"); do + CPATH="$CPATH:${file}" done - find ${CRAFT_STAGE} -type f -name *.jar | while IFS= read -r file; do - CPATH=$CPATH:${file} + for file in $(find "${CRAFT_STAGE}" -type f -name "*.jar"); do + CPATH="$CPATH:${file}" done """ ) commands.append( """if [ "x${PROCESS_JARS}" != "x" ]; then - deps=$(${JDEPS} --class-path=${CPATH} -q --recursive --ignore-missing-deps \ - --print-module-deps --multi-release ${MULTI_RELEASE} ${PROCESS_JARS}) + deps=$(${JDEPS} --print-module-deps -q --recursive \ + --ignore-missing-deps \ + --multi-release ${MULTI_RELEASE} \ + --class-path=${CPATH} \ + ${PROCESS_JARS}) else deps=java.base fi diff --git a/docs/common/craft-parts/craft-parts.wordlist.txt b/docs/common/craft-parts/craft-parts.wordlist.txt index 89d1bb9af..90c0c3ff4 100644 --- a/docs/common/craft-parts/craft-parts.wordlist.txt +++ b/docs/common/craft-parts/craft-parts.wordlist.txt @@ -44,6 +44,7 @@ Config ConfigDict CopyFileNotFound CopyTreeError +CPATH CraftCtl Craftctl DESTDIR diff --git a/docs/reference/changelog.rst b/docs/reference/changelog.rst index beda40ffb..875d2956c 100644 --- a/docs/reference/changelog.rst +++ b/docs/reference/changelog.rst @@ -2,6 +2,16 @@ Changelog ********* +2.5.1 (2025-02-12) +------------------ + +Bug fixes: + +- Fix CPATH variable scope in the :ref:`jlink plugin`. +- Fix Jdeps parameter ordering in the + :ref:`jlink plugin`. + + 2.3.1 (2025-02-07) ------------------ diff --git a/tests/integration/plugins/test_jlink.py b/tests/integration/plugins/test_jlink.py index f7a6665a1..05a599982 100644 --- a/tests/integration/plugins/test_jlink.py +++ b/tests/integration/plugins/test_jlink.py @@ -23,6 +23,72 @@ from craft_parts import LifecycleManager, Step, errors +@pytest.fixture +def build_test_jar(new_dir): + Path("Test.java").write_text( + """ + public class Test { + public static void main(String[] args) { + new Embedded(); + } + } + """ + ) + Path("Embedded.java").write_text( + """ + import javax.swing.*; + public class Embedded { + public Embedded() { + new JFrame("foo").setVisible(true); + } + } + + """ + ) + subprocess.run( + ["javac", "Test.java", "Embedded.java"], check=True, capture_output=True + ) + subprocess.run( + ["jar", "cvf", "embedded.jar", "Embedded.class"], + check=True, + capture_output=True, + ) + subprocess.run( + ["jar", "cvf", "test.jar", "Test.class", "embedded.jar"], + check=True, + capture_output=True, + ) + + +@pytest.mark.usefixtures("build_test_jar") +def test_jlink_plugin_embedded_jar(new_dir, partitions): + parts_yaml = textwrap.dedent( + """ + parts: + my-part: + plugin: jlink + source: . + jlink-jars: ["test.jar"] + after: ["stage-jar"] + stage-jar: + plugin: dump + source: . + """ + ) + parts = yaml.safe_load(parts_yaml) + + lf = LifecycleManager( + parts, application_name="test_jlink", cache_dir=new_dir, partitions=partitions + ) + actions = lf.plan(Step.PRIME) + + with lf.action_executor() as ctx: + ctx.execute(actions) + + # java.desktop module should be included in the image + assert len(list(Path(f"{new_dir}/stage/usr/lib/jvm/").rglob("libawt.so"))) > 0 + + def test_jlink_plugin_with_jar(new_dir, partitions): """Test that jlink produces tailored modules"""